diff --git a/app/src/adapter/cloudflare/connection/D1Connection.ts b/app/src/adapter/cloudflare/connection/D1Connection.ts index ddf6be84..b9713129 100644 --- a/app/src/adapter/cloudflare/connection/D1Connection.ts +++ b/app/src/adapter/cloudflare/connection/D1Connection.ts @@ -22,6 +22,7 @@ export class D1Connection< > extends SqliteConnection { protected override readonly supported = { batching: true, + counts: false, }; constructor(private config: D1ConnectionConfig) { diff --git a/app/src/data/api/DataController.ts b/app/src/data/api/DataController.ts index bc86a8df..2861ba3f 100644 --- a/app/src/data/api/DataController.ts +++ b/app/src/data/api/DataController.ts @@ -316,7 +316,7 @@ export class DataController extends Controller { return this.notFound(c); } const options = c.req.valid("query") as RepoQuery; - const result = await this.em.repository(entity).findMany(options); + const result = await this.em.repo(entity).findMany(options); return c.json(this.repoResult(result), { status: result.data ? 200 : 404 }); }, diff --git a/app/src/data/connection/Connection.ts b/app/src/data/connection/Connection.ts index 814c03d7..e7b0f09c 100644 --- a/app/src/data/connection/Connection.ts +++ b/app/src/data/connection/Connection.ts @@ -82,6 +82,7 @@ export abstract class Connection { kysely: Kysely; protected readonly supported = { batching: false, + counts: true, }; constructor( diff --git a/app/src/data/connection/DummyConnection.ts b/app/src/data/connection/DummyConnection.ts index d04d0afe..4b6b7603 100644 --- a/app/src/data/connection/DummyConnection.ts +++ b/app/src/data/connection/DummyConnection.ts @@ -3,6 +3,7 @@ import { Connection, type FieldSpec, type SchemaResponse } from "./Connection"; export class DummyConnection extends Connection { protected override readonly supported = { batching: true, + counts: true, }; constructor() { diff --git a/app/src/data/connection/sqlite/LibsqlConnection.ts b/app/src/data/connection/sqlite/LibsqlConnection.ts index 210f8cf9..11f92568 100644 --- a/app/src/data/connection/sqlite/LibsqlConnection.ts +++ b/app/src/data/connection/sqlite/LibsqlConnection.ts @@ -28,13 +28,13 @@ export class LibsqlConnection extends SqliteConnection { private client: Client; protected override readonly supported = { batching: true, + counts: false, }; constructor(client: Client); constructor(credentials: LibSqlCredentials); constructor(clientOrCredentials: Client | LibSqlCredentials) { let client: Client; - let batching_enabled = true; if (clientOrCredentials && "url" in clientOrCredentials) { let { url, authToken, protocol } = clientOrCredentials; if (protocol && LIBSQL_PROTOCOLS.includes(protocol)) { @@ -56,7 +56,6 @@ export class LibsqlConnection extends SqliteConnection { super(kysely, {}, plugins); this.client = client; - this.supported.batching = batching_enabled; } getClient(): Client { diff --git a/app/src/data/entities/query/Repository.ts b/app/src/data/entities/query/Repository.ts index 625e7013..13fcfc22 100644 --- a/app/src/data/entities/query/Repository.ts +++ b/app/src/data/entities/query/Repository.ts @@ -27,6 +27,7 @@ export type RepositoryResponse = RepositoryRawResponse & { data: T; meta: { items: number; + has_more?: boolean; total?: number; count?: number; time?: number; @@ -61,6 +62,10 @@ export class Repository { const entity = this.entity; + const compiled = qb.compile(); const payload = { @@ -444,6 +455,16 @@ export class Repository = { checkable?: boolean; onClickRow?: (row: Data) => void; onClickPage?: (page: number) => void; + hasMore?: boolean; total?: number; page?: number; perPage?: number; @@ -59,6 +60,7 @@ export function DataTable = Record onClickRow, onClickPage, onClickSort, + hasMore, total, sort, page = 1, @@ -75,7 +77,7 @@ export function DataTable = Record page = page || 1; const select = columns && columns.length > 0 ? columns : Object.keys(data?.[0] || {}); - const pages = Math.max(Math.ceil(total / perPage), 1); + const pages = hasMore === undefined ? Math.max(Math.ceil(total / perPage), 1) : undefined; const CellRender = renderValue || CellValue; return ( @@ -196,12 +198,14 @@ export function DataTable = Record
- + {hasMore === undefined ? ( + + ) : null}
{perPageOptions && ( @@ -220,11 +224,16 @@ export function DataTable = Record
)}
- Page {page} of {pages} + Page {page} {pages ? `of ${pages}` : ""}
{onClickPage && (
- +
)}
@@ -274,41 +283,59 @@ const TableDisplay = ({ perPage, page, items, total }) => { return <>Showing 1 row; } - return ( - <> - Showing {perPage * (page - 1) + 1}-{perPage * (page - 1) + items} of {total} rows - - ); + const text = `Showing ${perPage * (page - 1) + 1}-${perPage * (page - 1) + items}`; + if (total) { + return `${text} of ${total} rows`; + } + + return text; }; type TableNavProps = { current: number; - total: number; + total?: number; + hasMore?: boolean; onClick?: (page: number) => void; }; -const TableNav: React.FC = ({ current, total, onClick }: TableNavProps) => { +const TableNav: React.FC = ({ + current, + total: _total, + hasMore: _hasMore, + onClick, +}: TableNavProps) => { + const total = _total !== undefined ? _total : _hasMore !== undefined ? current + 1 : current; + const hasMore = _hasMore !== undefined ? _hasMore : current < (total ?? 0); + const navMap = [ { value: 1, Icon: TbChevronsLeft, disabled: current === 1 }, { value: current - 1, Icon: TbChevronLeft, disabled: current === 1 }, - { value: current + 1, Icon: TbChevronRight, disabled: current === total }, - { value: total, Icon: TbChevronsRight, disabled: current === total }, + { value: current + 1, Icon: TbChevronRight, disabled: !hasMore }, + { + value: _hasMore === undefined ? total : undefined, + Icon: TbChevronsRight, + disabled: !hasMore, + }, ] as const; - return navMap.map((nav, key) => ( - - )); + return navMap.map((nav, key) => { + const page = nav.value; + if (page === undefined) return null; + + return ( + + ); + }); }; diff --git a/app/src/ui/routes/data/data.$entity.index.tsx b/app/src/ui/routes/data/data.$entity.index.tsx index ee9befce..8aa2e250 100644 --- a/app/src/ui/routes/data/data.$entity.index.tsx +++ b/app/src/ui/routes/data/data.$entity.index.tsx @@ -131,6 +131,7 @@ export function DataEntityList({ params }) { perPage={search.value.perPage} perPageOptions={PER_PAGE_OPTIONS} total={meta?.count} + hasMore={meta?.has_more} onClickPage={handleClickPage} onClickPerPage={handleClickPerPage} />