Skip to content

Commit

Permalink
Migrate to @mui/x-date-pickers for date pickers
Browse files Browse the repository at this point in the history
  • Loading branch information
jamerst committed Jul 27, 2022
1 parent bd2480d commit e8e15a5
Show file tree
Hide file tree
Showing 21 changed files with 266 additions and 258 deletions.
6 changes: 3 additions & 3 deletions packages/base/FilterBuilder/components/FilterBuilder.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ import FilterRoot from "./FilterRoot";

import { ExternalBuilderProps, FieldDef } from "../types"

export type FilterBuilderProps = ExternalBuilderProps & {
schema: FieldDef[]
export type FilterBuilderProps<TDate = any> = ExternalBuilderProps<TDate> & {
schema: FieldDef<TDate>[]
}

const FilterBuilder = (props: FilterBuilderProps) => {
const FilterBuilder = <TDate,>(props: FilterBuilderProps<TDate>) => {
return (
<RecoilRoot override>
<FilterRoot props={props}/>
Expand Down
14 changes: 7 additions & 7 deletions packages/base/FilterBuilder/components/FilterInputs.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { Fragment, useMemo } from "react"
import { useRecoilValue } from "recoil";
import { Autocomplete, FormControl, Grid, InputLabel, MenuItem, Select, TextField } from "@mui/material";
import { DatePicker, DateTimePicker, LocalizationProvider } from "@mui/lab";
import { DatePicker, DateTimePicker, LocalizationProvider } from "@mui/x-date-pickers";

import { CollectionFieldDef, CollectionOperation, FieldDef, Operation } from "../types";

Expand All @@ -25,7 +25,7 @@ type FilterInputsProps = {
onCollectionFieldChange: (field: string, oldField: string | undefined, currentOp: Operation, newField: string | undefined) => void,
}

const FilterInputs = React.memo(({
const FilterInputs = <TDate,>({
clauseId,
field,
onFieldChange,
Expand All @@ -49,7 +49,7 @@ const FilterInputs = React.memo(({
return null;
}

let f: FieldDef;
let f: FieldDef<TDate>;
if (field) {
f = schema.find(c => c.field === field) ?? schema[0];
} else {
Expand All @@ -61,7 +61,7 @@ const FilterInputs = React.memo(({
}

let filterField = field;
let colField: CollectionFieldDef | undefined;
let colField: CollectionFieldDef<TDate> | undefined;
let type = f.filterType ?? f.type;
let options = f.valueOptions;
let ops = f.filterOperators ?? allOperators;
Expand Down Expand Up @@ -266,7 +266,7 @@ const FilterInputs = React.memo(({
{...builderProps.textFieldProps}
{...fieldDef.textFieldProps}
value={value ?? ""}
onChange={(e) => onValueChange(fieldDef.type === "number" ? parseFloat(e.target.value) : e.target.value)}
onChange={(e: React.ChangeEvent<HTMLInputElement | HTMLTextAreaElement>) => onValueChange(fieldDef.type === "number" ? parseFloat(e.target.value) : e.target.value)}
type={fieldDef.type === "number" ? "number" : "text"}
/>
}
Expand All @@ -276,6 +276,6 @@ const FilterInputs = React.memo(({
}
</Fragment>
)
});
};

export default FilterInputs;
export default React.memo(FilterInputs);
8 changes: 4 additions & 4 deletions packages/base/FilterBuilder/components/FilterRoot.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ import { useMountEffect } from "../../hooks";
import { ConditionClause, SerialisedGroup, QueryStringCollection } from "../types";
import { deserialise } from "../utils";

type FilterRootProps = {
props: FilterBuilderProps
type FilterRootProps<TDate> = {
props: FilterBuilderProps<TDate>
}

const FilterRoot = ({ props }: FilterRootProps) => {
const FilterRoot = <TDate,>({ props }: FilterRootProps<TDate>) => {
const setClauses = useSetRecoilState(clauseState);
const setProps = useSetRecoilState(propsState);
const setSchema = useSetRecoilState(schemaState);
Expand Down Expand Up @@ -176,7 +176,7 @@ const FilterRoot = ({ props }: FilterRootProps) => {
props.searchMenuItems &&
<Button
size="small"
onClick={(e) => setAnchor(e.currentTarget)}
onClick={(e: React.MouseEvent<HTMLButtonElement, MouseEvent>) => setAnchor(e.currentTarget)}
aria-controls={anchor !== null ? "search-menu": undefined}
aria-expanded={anchor !== null ? "true": undefined}
aria-haspopup="menu"
Expand Down
18 changes: 9 additions & 9 deletions packages/base/FilterBuilder/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,22 @@ import { useRecoilValue, waitForAll } from "recoil"
import { rootGroupUuid } from "./constants";
import { clauseState, schemaState, treeState } from "./state"
import { defaultTranslators } from "./translation";
import { BaseFieldDef, SerialisedCondition, ConditionClause, FieldDef, SerialisedGroup, GroupClause, Operation, QueryStringCollection, StateClause, StateTree, TreeGroup, FilterCompute, FilterTranslator } from "./types";
import { BaseFieldDef, SerialisedCondition, ConditionClause, FieldDef, SerialisedGroup, GroupClause, Operation, QueryStringCollection, StateClause, StateTree, TreeGroup, FilterTranslator } from "./types";

export const UseODataFilter = () => {
export const UseODataFilter = <TDate,>() => {
const schema = useRecoilValue(schemaState);
const [clauses, tree] = useRecoilValue(waitForAll([clauseState, treeState]));

return useCallback(() => {
return buildGroup(schema, clauses, tree, rootGroupUuid, []) as BuiltQuery<SerialisedGroup>;
return buildGroup<TDate>(schema, clauses, tree, rootGroupUuid, []) as BuiltQuery<SerialisedGroup>;
}, [schema, clauses, tree]);
}

export const UseODataFilterWithState = () => {
export const UseODataFilterWithState = <TDate,>() => {
const schema = useRecoilValue(schemaState);

return useCallback((clauses: StateClause, tree: StateTree) => {
return buildGroup(schema, clauses, tree, rootGroupUuid, []) as BuiltQuery<SerialisedGroup>;
return buildGroup<TDate>(schema, clauses, tree, rootGroupUuid, []) as BuiltQuery<SerialisedGroup>;
}, [schema])
}

Expand All @@ -33,7 +33,7 @@ type BuiltQuery<T> = BuiltInnerQuery & {
serialised: T
}

const buildGroup = (schema: FieldDef[], clauses: StateClause, tree: StateTree, id: string, path: string[]): (BuiltQuery<SerialisedGroup> | boolean) => {
const buildGroup = <TDate,>(schema: FieldDef<TDate>[], clauses: StateClause, tree: StateTree, id: string, path: string[]): (BuiltQuery<SerialisedGroup> | boolean) => {
const clause = clauses.get(id) as GroupClause;
const treeNode = tree.getIn([...path, id]) as TreeGroup;

Expand Down Expand Up @@ -75,7 +75,7 @@ const buildGroup = (schema: FieldDef[], clauses: StateClause, tree: StateTree, i
}
}

const buildCondition = (schema: FieldDef[], clauses: StateClause, id: string): (BuiltQuery<SerialisedCondition> | boolean) => {
const buildCondition = <TDate,>(schema: FieldDef<TDate>[], clauses: StateClause, id: string): (BuiltQuery<SerialisedCondition> | boolean) => {
const clause = clauses.get(id) as ConditionClause;

let condition: SerialisedCondition | undefined = undefined;
Expand Down Expand Up @@ -134,7 +134,7 @@ const buildCondition = (schema: FieldDef[], clauses: StateClause, id: string): (
}
}

const buildInnerCondition = (schema: BaseFieldDef, field: string, op: Operation, value: any): BuiltInnerQuery | boolean => {
const buildInnerCondition = <TDate,>(schema: BaseFieldDef<TDate>, field: string, op: Operation, value: any): BuiltInnerQuery | boolean => {
if (schema.getCustomQueryString) {
return {
queryString: schema.getCustomQueryString(op, value)
Expand Down Expand Up @@ -167,7 +167,7 @@ const buildInnerCondition = (schema: BaseFieldDef, field: string, op: Operation,
}
}

let translator: FilterTranslator;
let translator: FilterTranslator<TDate>;
if (op in defaultTranslators) {
translator = defaultTranslators[op]!;
} else {
Expand Down
4 changes: 2 additions & 2 deletions packages/base/FilterBuilder/state.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { atom } from "recoil"
import { ExternalBuilderProps, FieldDef } from "./types"
import { initialTree, initialClauses } from "./constants";

export const schemaState = atom<FieldDef[]>({
export const schemaState = atom<FieldDef<any>[]>({
key: "schema",
default: []
});
Expand All @@ -18,7 +18,7 @@ export const treeState = atom({
default: initialTree
});

export const propsState = atom<ExternalBuilderProps>({
export const propsState = atom<ExternalBuilderProps<any>>({
key: "props",
default: {}
});
2 changes: 1 addition & 1 deletion packages/base/FilterBuilder/translation.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { FilterTranslatorCollection } from "./types";
import { escapeODataString } from "./utils";

export const defaultTranslators: FilterTranslatorCollection = {
export const defaultTranslators: FilterTranslatorCollection<any> = {
"contains": (schema, field, op, value) => {
if ((schema.type && schema.type !== "string") || typeof value !== "string") {
console.warn(`Warning: operation "contains" is only supported for fields of type "string"`);
Expand Down
26 changes: 13 additions & 13 deletions packages/base/FilterBuilder/types.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import React from "react";
import { DatePickerProps, DateTimePickerProps, LocalizationProviderProps } from "@mui/lab";
import { DatePickerProps, DateTimePickerProps, LocalizationProviderProps } from "@mui/x-date-pickers";
import { AutocompleteProps, FormControlProps, SelectProps, TextFieldProps } from "@mui/material";
import { GridValueOptionsParams } from "@mui/x-data-grid";
import { ValueOption } from "../types";

export type ExternalBuilderProps = {
export type ExternalBuilderProps<TDate = any> = {
searchMenuItems?: ({ label: string, onClick: () => void })[],
onSubmit?: (params: FilterParameters) => (void | any),
onRestoreState?: (params: FilterParameters, state?: any) => void,
Expand All @@ -13,8 +13,8 @@ export type ExternalBuilderProps = {
autocompleteGroups?: string[],

autocompleteProps?: AutocompleteProps<any, any, any, any>,
datePickerProps?: DatePickerProps,
dateTimePickerProps?: DateTimePickerProps,
datePickerProps?: DatePickerProps<string, TDate>,
dateTimePickerProps?: DateTimePickerProps<string, TDate>,
localizationProviderProps?: LocalizationProviderProps,
selectProps?: SelectProps,
textFieldProps?: TextFieldProps,
Expand Down Expand Up @@ -63,13 +63,13 @@ export type FilterBuilderLocaleText = {
opNotNull?: string
}

export type BaseFieldDef = {
export type BaseFieldDef<TDate> = {
field: string,
autocompleteGroup?: string,
caseSensitive?: boolean,

datePickerProps?: DatePickerProps,
dateTimePickerProps?: DateTimePickerProps,
datePickerProps?: DatePickerProps<string, TDate>,
dateTimePickerProps?: DateTimePickerProps<string, TDate>,

filterable?: boolean,
filterField?: string,
Expand All @@ -93,13 +93,13 @@ export type BaseFieldDef = {
valueOptions?: ValueOption[] | ((params: GridValueOptionsParams) => ValueOption[]),
}

export type FieldDef = BaseFieldDef & {
export type FieldDef<TDate = any> = BaseFieldDef<TDate> & {
headerName?: string,
collection?: boolean,
collectionFields?: CollectionFieldDef[],
collectionFields?: CollectionFieldDef<TDate>[],
}

export type CollectionFieldDef = BaseFieldDef;
export type CollectionFieldDef<TDate = any> = BaseFieldDef<TDate>;

export type FilterCompute = {
filter: string,
Expand All @@ -115,11 +115,11 @@ export type QueryStringCollection = {
[key: string]: string
}

export type FilterTranslatorCollection = {
[key in Operation | "default"]?: FilterTranslator
export type FilterTranslatorCollection<TDate> = {
[key in Operation | "default"]?: FilterTranslator<TDate>
}

export type FilterTranslator = (schema: BaseFieldDef, field: string, op: Operation, value: any) => string | boolean;
export type FilterTranslator<TDate> = (schema: BaseFieldDef<TDate>, field: string, op: Operation, value: any) => string | boolean;

export type Connective = "and" | "or"

Expand Down
30 changes: 5 additions & 25 deletions packages/base/components/ODataGridBase.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,18 @@ import { ResponsiveValues, useResponsive } from "../hooks";

import FilterBuilder from "../FilterBuilder/components/FilterBuilder";

import { Expand, ODataResponse, ODataGridBaseProps, IGridSortModel, IGridProps, IGridRowModel, ColumnVisibilityModel } from "../types";
import { ODataResponse, ODataGridBaseProps, IGridSortModel, IGridProps, IGridRowModel, ColumnVisibilityModel } from "../types";

import { ExpandToQuery, Flatten, GroupArrayBy, GetPageNumber, GetPageSizeOrDefault } from "../utils";
import { ExpandToQuery, Flatten, GetPageNumber, GetPageSizeOrDefault } from "../utils";

import { defaultPageSize } from "../constants";
import { SerialisedGroup, QueryStringCollection, FilterParameters } from "../FilterBuilder/types";
import { QueryStringCollection, FilterParameters } from "../FilterBuilder/types";
import { GridColumnVisibilityModel } from "@mui/x-data-grid";

const ODataGridBase = <ComponentProps extends IGridProps,
SortModel extends IGridSortModel,
ColDef,>(props: ODataGridBaseProps<ComponentProps, SortModel, ColDef>) => {
ColDef,
TDate,>(props: ODataGridBaseProps<ComponentProps, SortModel, ColDef, TDate>) => {

const [pageNumber, setPageNumber] = useState<number>(GetPageNumber());
const [pageSize, setPageSize] = useState<number>(GetPageSizeOrDefault(props.defaultPageSize));
Expand Down Expand Up @@ -76,27 +77,6 @@ const ODataGridBase = <ComponentProps extends IGridProps,
.filter(c => visibleColumns.includes(c.field) && c.expand)
.map(c => c.expand!);

// group all expands by the navigation field
// const groupedExpands = GroupArrayBy(
// props.columns
// .filter(c => visibleColumns.includes(c.field) && !!c.expand)
// .map(c => c.expand!),
// (e) => e.navigationField
// );

// // construct a single expand for each navigation field, combining nested query options
// const expands: Expand[] = [];
// groupedExpands.forEach((e, k) => {
// expands.push({
// navigationField: k,
// top: e.find(e2 => e2.top)?.top,
// orderBy: e.find(e2 => e2.orderBy)?.orderBy,
// count: e.some(e2 => e2.count),
// select: Array.from(new Set(e.filter(e2 => e2.select).map(e2 => e2.select))).join(","),
// expand: e.find(e2 => e2.expand)
// });
// });

const query = new URLSearchParams();
query.append("$select", Array.from(fields).join(","));
query.append("$expand", ExpandToQuery(expands));
Expand Down
2 changes: 1 addition & 1 deletion packages/base/hooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export const useBreakpoints = ():Partial<Record<Breakpoint, boolean>> => {
const [matches, setMatches] = useState<Partial<Record<Breakpoint, boolean>>>(getMatches(theme.breakpoints.keys, theme));

useEffect(() => {
const queries = getQueries(theme.breakpoints.keys, theme);
const queries: Partial<Record<Breakpoint, MediaQueryList>> = getQueries(theme.breakpoints.keys, theme);
const listeners: Partial<Record<Breakpoint, () => void>> = {};

const updateMatch = (b: Breakpoint) => {
Expand Down
9 changes: 5 additions & 4 deletions packages/base/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,23 @@ import React from "react";
export type ODataGridBaseProps<
ComponentProps extends IGridProps,
SortModel extends IGridSortModel,
ColDef
ColDef,
TDate
> =
OmitGridProps<ComponentProps>
&
{
url: string,
alwaysSelect?: string[],
columns: ODataGridBaseColDef<ColDef>[],
columns: ODataGridBaseColDef<ColDef, TDate>[],
columnVisibilityModel?: ODataColumnVisibilityModel,
component: React.ElementType,
defaultPageSize?: number,
defaultSortModel?: SortModel,
disableFilterBuilder?: boolean,
disableHistory?: boolean,
$filter?: string,
filterBuilderProps?: ExternalBuilderProps,
filterBuilderProps?: ExternalBuilderProps<TDate>,
requestOptions?: RequestInit
};

Expand All @@ -46,7 +47,7 @@ type OmitGridProps<T> = Omit<T,
| "sortModel"
>

export type ODataGridBaseColDef<ColDef> = Omit<ColDef, "filterOperators" | "hide" | "sortComparator"> & FieldDef & {
export type ODataGridBaseColDef<ColDef, TDate> = Omit<ColDef, "filterOperators" | "hide" | "sortComparator"> & FieldDef<TDate> & {
select?: string,
expand?: Expand,
hide?: ResponsiveValues<boolean> | boolean,
Expand Down
4 changes: 2 additions & 2 deletions packages/base/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { Expand } from "./types";
import { defaultPageSize } from "./constants";

/**
* Convert an Expand object to a clause to use in an OData $expand query parameter
* @param e Expand to convert
* Convert an Expand object (or array of objects) to a clause to use in an OData $expand query parameter
* @param e Expand(s) to convert
* @returns OData expand clause string
*/
export const ExpandToQuery = (expand?: Expand[] | Expand): string => {
Expand Down
5 changes: 4 additions & 1 deletion packages/o-data-grid-pro/dev/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@ import { ODataGridColDef, ODataColumnVisibilityModel, escapeODataString } from "
import ODataGridPro from "../src/ODataGridPro";
import { CacheProvider } from "@emotion/react";
import createCache from "@emotion/cache";
import { AdapterDayjs } from "@mui/x-date-pickers/AdapterDayjs";
import { Dayjs } from "dayjs";
import { ExternalBuilderProps } from "../../base/FilterBuilder/types";

const theme = createTheme({
palette: {
Expand Down Expand Up @@ -42,7 +45,7 @@ type LocationFilter = {
distance?: number
}

const filterBuilderProps = { autocompleteGroups: ["Job", "Company"] };
const filterBuilderProps: ExternalBuilderProps<Dayjs> = { autocompleteGroups: ["Job", "Company"], localizationProviderProps: { dateAdapter: AdapterDayjs } };

const alwaysFetch = ["Id", "Archived"];
const columns: ODataGridColDef[] = [
Expand Down
Loading

0 comments on commit e8e15a5

Please sign in to comment.