ServerQueryManager#

@palmyralabs/rt-forms · src/palmyra/wire/ServerQueryManager.tsx

Overview#

Not a component — the file’s single runtime export is the useServerQuery hook. It manages the filter / sort / pagination state of a server-backed grid against a Wire GridStore, and returns an imperative handle (IPageQueryable) that grid templates consume.

If no store is passed in, the hook reaches for StoreFactoryContext and asks the factory for a grid store keyed on endPoint + storeOptions. That’s the seam that makes grids and forms share the same factory configuration.

Signature#

function useServerQuery(props: IServerQueryInput): IPageQueryable;

Props — IServerQueryInput#

interface IServerQueryInput extends AbstractHandler {
  store?:          AbstractQueryStore<any> & { export?(r: ExportRequest): void };
  endPoint?:       IEndPoint;
  storeOptions?:   StoreOptions;
  fields?:         string[];
  fetchAll?:       boolean;
  defaultParams?:  DefaultQueryParams;
  onDataChange?:   (newData: any[], oldData?: any[]) => void;
  pageSize?:       number | number[];
  quickSearch?:    string;
  filterTopic?:    string;
  initialFetch?:   boolean;
  initParams?: {
    filter?: any;
    sort?:   string | string[];
    limit?:  number;
    offset?: number;
  };
}

Return — IPageQueryable#

interface IQueryable {
  setQuickSearch(q: string): void;
  setFilter(f: any): void;
  addFilter(f: any): void;
  resetFilter(): void;
  setSortColumns(sort: string | string[]): void;
  setEndPointOptions(opts: Record<string, any>): void;
  refresh(): void;
  getCurrentData(): any[];
  export(req: ExportRequest): void;
  isLoading(): boolean;
}

interface IPageQueryable extends IQueryable {
  setQueryLimit(limit: number): void;
  getQueryLimit(): number;
  gotoPage(n: number): void;
  nextPage(): void;
  prevPage(): void;
  setPageSize(sizes: number | number[]): void;
  getPageNo(): number;
  getQueryRequest(): QueryRequest;
  getCurrentFilter(): any;
  getTotalPages(): number;
  getTotalRecords(): number;
}

Example — hook-driven grid#

import { useRef } from 'react';
import { useServerQuery, type IPageQueryable } from '@palmyralabs/rt-forms';
import { Table, Pagination, TextInput, Group } from '@mantine/core';

export function ManufacturersGrid() {
  const q: IPageQueryable = useServerQuery({
    endPoint: '/mstManufacturer',
    pageSize: [15, 30, 45],
    initParams: { sort: ['-id'], limit: 15, offset: 0 },
    initialFetch: true,
  });

  const rows = q.getCurrentData();

  return (
    <>
      <TextInput placeholder="Search"
                 onChange={e => q.setQuickSearch(e.currentTarget.value)} mb="md" />
      <Table>
        <Table.Tbody>
          {rows.map((r: any) => (
            <Table.Tr key={r.id}>
              <Table.Td>{r.name}</Table.Td>
              <Table.Td>{r.contactMobile}</Table.Td>
            </Table.Tr>
          ))}
        </Table.Tbody>
      </Table>
      <Group justify="flex-end">
        <Pagination total={q.getTotalPages()} value={q.getPageNo()} onChange={q.gotoPage} />
      </Group>
    </>
  );
}

SummaryGrid and similar templates just pass their own props into useServerQuery and wire the returned IPageQueryable to the toolbar, table, and paginator — you can build the same thing by hand when you need a non-standard chrome.