Filters
The view below is grid/Filters from qlive-test, unchanged, running in your
browser on data recorded from the running application. Each column has one of
the filters QLive ships: a name pattern such as *#2* | *#1*, an operator on
num, the digits anywhere in it, yes or no for the flag, the owner picked from
the users, and a range of whole days for the creation date.
import { DataGrid, numberContainsFilter, operatorFilter, patternFilter, pick, useInjection} from "@qlivedev/qlive-ts";import { Q_FooList, Q_FooListResult } from "./Q_FooList";import { Q_OwnerCatalog } from "../Q_OwnerCatalog";
/** * The filters QLive ships, one per column. A filter is a value the view imports and hands to the column; there is no * registry to look it up in, so one of the application's own is passed the same way. */export default function Filters(){ const foos: Q_FooListResult = useInjection(Q_FooList, {config: {pageSize: 5}});
// the users to pick an owner from, all of them, since there are few enough const owners = useInjection(Q_OwnerCatalog, {config: {pageSize: 0, sortFields: ["login"]}});
return ( <div className="grid-example"> <h1>Filters</h1> <DataGrid doc={ foos } columns={ [ // "*#2* | *#1*": the pattern matches the whole name, * is any text, & and | combine, ! negates {field: "name", filter: patternFilter()},
// any FilterDSL operator; between takes two inputs {field: "num", filter: operatorFilter("between", "Int")},
// the digits anywhere in the number: "2" finds 123 {field: "num", heading: "Num contains", filter: numberContainsFilter()},
// the default for a Boolean: any, yes or no "flag",
// the users of the catalog, filtering the foreign key {field: "owner", filter: pick(owners)},
// the default for a Timestamp: whole days in the user's time zone, open at either end {field: "created", nowrap: true} ] } /> </div> );}Next to another view
Section titled “Next to another view”grid/Sorting runs below on its own fixture. Both views inject the same query,
Q_FooList, each with its own config and rows. They don’t mix, because an
injection is keyed by the route of the view that injects it:
grid/filters/Q_FooList above, grid/sorting/Q_FooList here. Filter one, sort
the other.
import {DataGrid, decompileFilter, i18n, ResolvedColumn, unawaited, useInjection} from "@qlivedev/qlive-ts";import {CNode, field, FieldExpression, matchSort, matchSortPart, value} from "@qlivedev/qlive-ts/filter";import { Q_FooList, Q_FooListResult } from "./Q_FooList";import FilterDSLPrinter, {sortExpression} from "../../component/FilterDSLPrinter";import filterAsTitle from "../../util/filterAsTitle";import React from "react";
/** * Sort orders a header click can't set, offered by a control of the view's own. * * A header click always sorts by that column alone. Anything more -- several fields, an expression -- is set on the * document from outside, and the headers show it as well as they can: the direction and the position of each field * in the order. A column whose field takes part in an expression, like num in its last digit, shows the expression's * direction and position in a color of its own. */const ORDERS = [ {label: i18n("Owner, then name"), sortFields: ["owner.login", "name"]}, {label: i18n("Flagged first, then largest num"), sortFields: ["!flag", "!num"]}, {label: i18n("Last digit of num"), sortFields: [field("num").mod(value(10))]}, {label: i18n("Owner, then last digit of num"), sortFields: ["owner.login", field("num").mod(value(10))]}];
export default function Sorting(){ const foos: Q_FooListResult = useInjection(Q_FooList, {config: {pageSize: 5}}); const {sortFields} = foos.config;
return ( <> <div className="grid-example"> <h1>Sort orders</h1> <p> <select value="" onChange={ ev => unawaited(foos.update({sortFields: ORDERS[Number(ev.target.value)].sortFields, offset: 0})) } > <option value="" disabled>{ i18n("Sort by …") }</option> { ORDERS.map((order, i) => <option key={ i } value={ i }>{ order.label }</option>) } </select> </p> <DataGrid doc={ foos } columns={ ["name", "num", "flag", "owner"] } headerTitle={ filterAsTitle(foos.config) }/> </div>
<p> { i18n("Current sorting order") } </p> <FilterDSLPrinter value={sortFields}/> </> );}