Skip to content

Commit

Permalink
Make it a component
Browse files Browse the repository at this point in the history
  • Loading branch information
Artur- committed Sep 12, 2023
1 parent 1ed260e commit 0c7696d
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 68 deletions.
116 changes: 67 additions & 49 deletions packages/ts/react-grid/src/autogrid.tsx
Original file line number Diff line number Diff line change
@@ -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";
Expand All @@ -13,54 +19,57 @@ enum Direction {
DESC = 'DESC',
}

export const useAutoGrid = <T,>(endpoint: CrudEndpoint<T>, itemType: ModelConstructor<T, any>) => {
const listMethod = endpoint.list;
const ref = useRef(null);

useEffect(() => {
const grid = ref.current as any as GridElement<T>;
export type _AutoGridProps<TItem> = {
service: CrudService<TItem>;
model: ModelConstructor<TItem, any>;
};
export type AutoGridProps<TItem> = GridProps<TItem> & _AutoGridProps<TItem>;

let first = true;
const createDataProvider = <TItem,>(grid: GridElement<TItem>, service: CrudService<TItem>) => {
const listMethod = service.list;
let first = true;

grid.dataProvider = async (params: GridDataProviderParams<T>, callback: GridDataProviderCallback<T>) => {
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<TItem>, callback: GridDataProviderCallback<TItem>) => {
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<any, any>) => {
const properties = getProperties(model);

const columns = properties.map((p) => {
let customProps: any = { autoWidth: true };

let column = (
Expand All @@ -69,9 +78,18 @@ export const useAutoGrid = <T,>(endpoint: CrudEndpoint<T>, itemType: ModelConstr

return column;
});

return {
ref,
children: [...children],
};
return columns;
};

export function AutoGrid<TItem>(props: AutoGridProps<TItem>) {
const ref = useRef(null);

useEffect(() => {
const grid = ref.current as any as GridElement<TItem>;
grid.dataProvider = createDataProvider(grid, props.service);
}, []);

const children = createColumns(props.model);

return <Grid {...props} ref={ref} children={children}></Grid>;
}
2 changes: 1 addition & 1 deletion packages/ts/react-grid/src/crud.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import Pageable from './types/Pageable';

export interface CrudEndpoint<T> {
export interface CrudService<T> {
list: {
(request: Pageable): Promise<T[]>;
};
Expand Down
32 changes: 14 additions & 18 deletions packages/ts/react-grid/test/autogrid.spec.tsx
Original file line number Diff line number Diff line change
@@ -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<Person> = {
const fakeService: CrudService<Person> = {
list: async (request: Pageable): Promise<Person[]> => {
const data: Person[] = [
{ firstName: 'John', lastName: 'Dove' },
Expand All @@ -33,20 +32,20 @@ async function sleep(ms: number) {
);
}
describe('@hilla/react-grid', () => {
type UseAutoGridSpy = sinon.SinonSpy<Parameters<typeof _useAutoGrid>, ReturnType<typeof _useAutoGrid>>;
const useAutoGrid = sinon.spy(_useAutoGrid) as typeof _useAutoGrid;
// type UseAutoGridSpy = sinon.SinonSpy<Parameters<typeof _useAutoGrid>, ReturnType<typeof _useAutoGrid>>;
// 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 <Grid {...autoGrid}></Grid>;
function TestAutoGrid() {
// const autoGrid = useAutoGrid(fakeEndpoint, PersonModel);
return <AutoGrid service={fakeService} model={PersonModel}></AutoGrid>;
}
describe('useAutoGrid', () => {
it('creates columns based on model', async () => {
const result = render(<AutoGrid />);
const result = render(<TestAutoGrid />);
const columns = result.container.querySelectorAll('vaadin-grid-sort-column');
expect(columns.length).to.equal(2);
expect(columns[0].path).to.equal('firstName');
Expand All @@ -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(<AutoGrid />);
const result = render(<TestAutoGrid />);
const grid = result.container.querySelector('vaadin-grid');
expect(grid?.dataProvider).to.not.be.undefined;
});
it('data provider provides data', async () => {
const result = render(<AutoGrid />);
const result = render(<TestAutoGrid />);
const grid: GridElement = result.container.querySelector('vaadin-grid')!;
grid.requestContentUpdate();
await sleep(1);
Expand All @@ -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;
}

0 comments on commit 0c7696d

Please sign in to comment.