From 456676d10c2874d80e17a7a7b553d2a5c2e65a4f Mon Sep 17 00:00:00 2001 From: Sidney Alcantara Date: Wed, 8 Jun 2022 17:34:18 +1000 Subject: [PATCH] support filtering by document ID (#668) --- src/components/Table/ColumnSelect.tsx | 17 ++++++------ .../TableToolbar/Filters/FilterInputs.tsx | 25 +++++++++++------- .../TableToolbar/Filters/FiltersPopover.tsx | 5 ++-- .../TableToolbar/Filters/IdFilterInput.tsx | 26 +++++++++++++++++++ .../TableToolbar/Filters/useFilterInputs.ts | 24 ++++++++++++++--- src/components/fields/types.ts | 8 +----- src/hooks/useFirestoreCollectionWithAtom.ts | 4 +++ src/types/table.d.ts | 3 ++- 8 files changed, 82 insertions(+), 30 deletions(-) create mode 100644 src/components/TableToolbar/Filters/IdFilterInput.tsx diff --git a/src/components/Table/ColumnSelect.tsx b/src/components/Table/ColumnSelect.tsx index 11a6ad07..ab235f11 100644 --- a/src/components/Table/ColumnSelect.tsx +++ b/src/components/Table/ColumnSelect.tsx @@ -29,16 +29,17 @@ export default function ColumnSelect({ ...props }: IColumnSelectProps & Omit, "options">) { const [tableColumnsOrdered] = useAtom(tableColumnsOrderedAtom, tableScope); - const options = ( - filterColumns + const options = + props.options || + (filterColumns ? tableColumnsOrdered.filter(filterColumns) : tableColumnsOrdered - ).map(({ key, name, type, index }) => ({ - value: key, - label: name, - type, - index, - })); + ).map(({ key, name, type, index }) => ({ + value: key, + label: name, + type, + index, + })); return ( }> {columnType && - createElement(getFieldProp("SideDrawerField", columnType), { - column: selectedColumn, - _rowy_ref: {}, - value: query.value, - onChange: (value: any) => { - setQuery((query) => ({ ...query, value })); - }, - disabled, - })} + createElement( + query.key === "_rowy_ref.id" + ? IdFilterInput + : getFieldProp("filter.customInput" as any, columnType) || + getFieldProp("SideDrawerField", columnType), + { + column: selectedColumn, + _rowy_ref: {}, + value: query.value, + onChange: (value: any) => { + setQuery((query) => ({ ...query, value })); + }, + disabled, + } + )} )} diff --git a/src/components/TableToolbar/Filters/FiltersPopover.tsx b/src/components/TableToolbar/Filters/FiltersPopover.tsx index 59634f85..a2b2bee3 100644 --- a/src/components/TableToolbar/Filters/FiltersPopover.tsx +++ b/src/components/TableToolbar/Filters/FiltersPopover.tsx @@ -65,6 +65,7 @@ export default function FiltersPopover({ {appliedFilters.map((filter) => { + const fieldName = filter.key === "_rowy_ref.id" ? "ID" : filter.key; const operator = (availableFilters?.operators ?? []).find( (f) => f.value === filter.operator ); @@ -78,8 +79,8 @@ export default function FiltersPopover({ - {filter.key}{" "} + + {fieldName}{" "} void; +} + +export default function IdFilterInput({ + value, + onChange, +}: IIdFilterInputProps) { + return ( + onChange(e.target.value)} + value={value} + fullWidth + sx={{ + "& .MuiFilledInput-input": { + typography: "caption", + fontFamily: "mono", + }, + }} + /> + ); +} diff --git a/src/components/TableToolbar/Filters/useFilterInputs.ts b/src/components/TableToolbar/Filters/useFilterInputs.ts index 4025cad1..ae54ed42 100644 --- a/src/components/TableToolbar/Filters/useFilterInputs.ts +++ b/src/components/TableToolbar/Filters/useFilterInputs.ts @@ -2,6 +2,7 @@ import { useState } from "react"; import { find } from "lodash-es"; import { getFieldType, getFieldProp } from "@src/components/fields"; +import { FieldType } from "@src/constants/fields"; import type { ColumnConfig, TableFilter } from "@src/types/table"; import type { IFieldConfig } from "@src/components/fields/types"; @@ -22,6 +23,15 @@ export const useFilterInputs = ( index: c.index, })); + // Always allow IDs to be filterable + filterColumns.push({ + value: "_rowy_ref.id", + label: "Document ID", + type: FieldType.id, + key: "_rowy_ref.id", + index: filterColumns.length, + }); + // State for filter inputs const [query, setQuery] = useState( defaultQuery || INITIAL_QUERY @@ -30,6 +40,11 @@ export const useFilterInputs = ( // When the user sets a new column, automatically set the operator and value const handleChangeColumn = (value: string | null) => { + if (value === "_rowy_ref.id") { + setQuery({ key: "_rowy_ref.id", operator: "id-equal", value: "" }); + return; + } + const column = find(filterColumns, ["key", value]); if (column) { @@ -47,9 +62,12 @@ export const useFilterInputs = ( // Get the column config const selectedColumn = find(filterColumns, ["key", query?.key]); // Get available filters from selected column type - const availableFilters: IFieldConfig["filter"] = selectedColumn - ? getFieldProp("filter", getFieldType(selectedColumn)) - : undefined; + const availableFilters: IFieldConfig["filter"] = + query?.key === "_rowy_ref.id" + ? { operators: [{ value: "id-equal", label: "is" }] } + : selectedColumn + ? getFieldProp("filter", getFieldType(selectedColumn)) + : undefined; return { filterColumns, diff --git a/src/components/fields/types.ts b/src/components/fields/types.ts index 1c14f683..a87a1bce 100644 --- a/src/components/fields/types.ts +++ b/src/components/fields/types.ts @@ -36,7 +36,7 @@ export interface IFieldConfig { settingsValidator?: (config: Record) => Record; filter?: { operators: IFilterOperator[]; - customInput?: React.ComponentType; + customInput?: React.ComponentType<{ onChange: (value: any) => void }>; defaultValue?: any; valueFormatter?: (value: any) => string; }; @@ -101,12 +101,6 @@ export interface ISettingsProps { errors: Record; } -// TODO: WRITE TYPES -export interface IFiltersProps { - onChange: (key: string) => (value: any) => void; - [key: string]: any; -} - export interface IFilterOperator { value: TableFilter["operator"]; label: string; diff --git a/src/hooks/useFirestoreCollectionWithAtom.ts b/src/hooks/useFirestoreCollectionWithAtom.ts index db76cc79..1af70473 100644 --- a/src/hooks/useFirestoreCollectionWithAtom.ts +++ b/src/hooks/useFirestoreCollectionWithAtom.ts @@ -22,6 +22,7 @@ import { Query, QueryConstraint, WhereFilterOp, + documentId, } from "firebase/firestore"; import { useErrorHandler } from "react-error-boundary"; @@ -358,6 +359,9 @@ export const tableFiltersToFirestoreFilters = (filters: TableFilter[]) => { firestoreFilters.push(where(filter.key, ">=", startDate)); firestoreFilters.push(where(filter.key, "<=", endDate)); continue; + } else if (filter.operator === "id-equal") { + firestoreFilters.push(where(documentId(), "==", filter.value)); + continue; } firestoreFilters.push( diff --git a/src/types/table.d.ts b/src/types/table.d.ts index 1539eede..4fae39f6 100644 --- a/src/types/table.d.ts +++ b/src/types/table.d.ts @@ -152,7 +152,8 @@ export type TableFilter = { | "date-after" | "date-before-equal" | "date-after-equal" - | "time-minute-equal"; + | "time-minute-equal" + | "id-equal"; value: any; };