mirror of
https://github.com/rowyio/rowy.git
synced 2025-12-29 00:16:39 +01:00
update date & time filter operators for clarity
This commit is contained in:
@@ -1,16 +1,21 @@
|
||||
import { Suspense, createElement } from "react";
|
||||
import { ErrorBoundary } from "react-error-boundary";
|
||||
|
||||
import {
|
||||
Grid,
|
||||
MenuItem,
|
||||
ListItemText,
|
||||
Divider,
|
||||
ListSubheader,
|
||||
Typography,
|
||||
TextField,
|
||||
InputLabel,
|
||||
} from "@mui/material";
|
||||
|
||||
import ColumnSelect from "@src/components/Table/ColumnSelect";
|
||||
import FieldSkeleton from "@src/components/SideDrawer/FieldSkeleton";
|
||||
import IdFilterInput from "./IdFilterInput";
|
||||
import { InlineErrorFallback } from "@src/components/ErrorFallback";
|
||||
|
||||
import type { useFilterInputs } from "./useFilterInputs";
|
||||
import { getFieldType, getFieldProp } from "@src/components/fields";
|
||||
@@ -30,6 +35,45 @@ export default function FilterInputs({
|
||||
}: IFilterInputsProps) {
|
||||
const columnType = selectedColumn ? getFieldType(selectedColumn) : null;
|
||||
|
||||
const operators = availableFilters?.operators ?? [];
|
||||
const renderedOperatorItems = operators.map((operator) => (
|
||||
<MenuItem key={operator.value} value={operator.value}>
|
||||
<ListItemText style={{ flexShrink: 0 }}>{operator.label}</ListItemText>
|
||||
|
||||
{operator.secondaryLabel && (
|
||||
<Typography
|
||||
variant="inherit"
|
||||
color="text.disabled"
|
||||
sx={{ overflow: "hidden", textOverflow: "ellipsis", ml: 1 }}
|
||||
>
|
||||
{operator.secondaryLabel}
|
||||
</Typography>
|
||||
)}
|
||||
</MenuItem>
|
||||
));
|
||||
|
||||
// Insert ListSubheader components in between groups of operators
|
||||
for (let i = 0; i < operators.length; i++) {
|
||||
if (!operators[i].group) continue;
|
||||
|
||||
if (i === 0 || operators[i - 1].group !== operators[i].group) {
|
||||
renderedOperatorItems.splice(
|
||||
i === 0 ? 0 : i + 1,
|
||||
0,
|
||||
<ListSubheader key={operators[i].group}>
|
||||
{operators[i].group}
|
||||
</ListSubheader>
|
||||
);
|
||||
|
||||
if (i > 0)
|
||||
renderedOperatorItems.splice(
|
||||
i + 1,
|
||||
0,
|
||||
<Divider key={`divider-${operators[i].group}`} variant="middle" />
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Grid container spacing={2} sx={{ mb: 3 }}>
|
||||
<Grid item xs={4}>
|
||||
@@ -65,29 +109,13 @@ export default function FilterInputs({
|
||||
<MenuItem disabled value="" style={{ display: "none" }}>
|
||||
Select operator
|
||||
</MenuItem>
|
||||
{availableFilters?.operators.map((operator) => (
|
||||
<MenuItem key={operator.value} value={operator.value}>
|
||||
<ListItemText style={{ flexShrink: 0 }}>
|
||||
{operator.label}
|
||||
</ListItemText>
|
||||
|
||||
{operator.secondaryLabel && (
|
||||
<Typography
|
||||
variant="inherit"
|
||||
color="text.disabled"
|
||||
style={{ overflow: "hidden", textOverflow: "ellipsis" }}
|
||||
>
|
||||
{operator.secondaryLabel}
|
||||
</Typography>
|
||||
)}
|
||||
</MenuItem>
|
||||
))}
|
||||
{renderedOperatorItems}
|
||||
</TextField>
|
||||
</Grid>
|
||||
|
||||
<Grid item xs={4}>
|
||||
<Grid item xs={4} key={query.key + query.operator}>
|
||||
{query.key && query.operator && (
|
||||
<>
|
||||
<ErrorBoundary FallbackComponent={InlineErrorFallback}>
|
||||
<InputLabel
|
||||
variant="filled"
|
||||
id={`filters-label-${query.key}`}
|
||||
@@ -111,10 +139,11 @@ export default function FilterInputs({
|
||||
setQuery((query) => ({ ...query, value }));
|
||||
},
|
||||
disabled,
|
||||
operator: query.operator,
|
||||
}
|
||||
)}
|
||||
</Suspense>
|
||||
</>
|
||||
</ErrorBoundary>
|
||||
)}
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
@@ -76,7 +76,7 @@ export default function FiltersPopover({
|
||||
|
||||
const formattedValue = availableFilters?.valueFormatter
|
||||
? availableFilters.valueFormatter(filter.value)
|
||||
: filter.value;
|
||||
: filter.value.toString();
|
||||
|
||||
return (
|
||||
<Chip
|
||||
|
||||
14
src/components/fields/DateTime/FilterCustomInput.tsx
Normal file
14
src/components/fields/DateTime/FilterCustomInput.tsx
Normal file
@@ -0,0 +1,14 @@
|
||||
import { IFilterCustomInputProps } from "@src/components/fields/types";
|
||||
import DateTimeInput from "./SideDrawerField";
|
||||
import DateInput from "@src/components/fields/Date/SideDrawerField";
|
||||
|
||||
export default function FilterCustomInput({
|
||||
onChange,
|
||||
operator,
|
||||
...props
|
||||
}: IFilterCustomInputProps) {
|
||||
if (operator && operator.startsWith("date-"))
|
||||
return <DateInput {...(props as any)} onChange={onChange} />;
|
||||
|
||||
return <DateTimeInput {...(props as any)} onChange={onChange} />;
|
||||
}
|
||||
@@ -14,7 +14,7 @@ import { getFieldId } from "@src/components/SideDrawer/utils";
|
||||
|
||||
export interface IDateProps extends ISideDrawerFieldProps {}
|
||||
|
||||
export default function Date_({
|
||||
export default function DateTime({
|
||||
column,
|
||||
value,
|
||||
onChange,
|
||||
|
||||
@@ -7,56 +7,67 @@ export const filterOperators: IFilterOperator[] = [
|
||||
label: "equals",
|
||||
secondaryLabel: "==",
|
||||
value: "time-minute-equal",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "not equal to",
|
||||
secondaryLabel: "!=",
|
||||
value: "!=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "before",
|
||||
secondaryLabel: "<",
|
||||
value: "<",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "after",
|
||||
secondaryLabel: ">",
|
||||
value: ">",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "before or at",
|
||||
secondaryLabel: "<=",
|
||||
value: "<=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "at or after",
|
||||
secondaryLabel: ">=",
|
||||
value: ">=",
|
||||
group: "Date & Time",
|
||||
},
|
||||
{
|
||||
label: "where date is is",
|
||||
label: "where date is",
|
||||
secondaryLabel: "date ==",
|
||||
value: "date-equal",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is before",
|
||||
secondaryLabel: "date <",
|
||||
value: "date-before",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is after",
|
||||
secondaryLabel: "date >",
|
||||
value: "date-after",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is before or on",
|
||||
secondaryLabel: "date <=",
|
||||
value: "date-before-equal",
|
||||
group: "Date",
|
||||
},
|
||||
{
|
||||
label: "where date is on or after",
|
||||
secondaryLabel: "date >=",
|
||||
value: "date-after-equal",
|
||||
group: "Date",
|
||||
},
|
||||
];
|
||||
|
||||
|
||||
@@ -21,6 +21,12 @@ const SideDrawerField = lazy(
|
||||
const Settings = lazy(
|
||||
() => import("./Settings" /* webpackChunkName: "Settings-DateTime" */)
|
||||
);
|
||||
const FilterCustomInput = lazy(
|
||||
() =>
|
||||
import(
|
||||
"./FilterCustomInput" /* webpackChunkName: "FilterCustomInput-DateTime" */
|
||||
)
|
||||
);
|
||||
|
||||
export const config: IFieldConfig = {
|
||||
type: FieldType.dateTime,
|
||||
@@ -34,7 +40,11 @@ export const config: IFieldConfig = {
|
||||
TableCell: withHeavyCell(BasicCell, TableCell),
|
||||
TableEditor: NullEditor as any,
|
||||
SideDrawerField,
|
||||
filter: { operators: filterOperators, valueFormatter },
|
||||
filter: {
|
||||
operators: filterOperators,
|
||||
valueFormatter,
|
||||
customInput: FilterCustomInput,
|
||||
},
|
||||
settings: Settings,
|
||||
csvImportParser: (value) => parseJSON(value).getTime(),
|
||||
csvExportFormatter: (value: any, config?: any) =>
|
||||
|
||||
@@ -35,7 +35,7 @@ export interface IFieldConfig {
|
||||
settingsValidator?: (config: Record<string, any>) => Record<string, string>;
|
||||
filter?: {
|
||||
operators: IFilterOperator[];
|
||||
customInput?: React.ComponentType<{ onChange: (value: any) => void }>;
|
||||
customInput?: React.ComponentType<IFilterCustomInputProps>;
|
||||
defaultValue?: any;
|
||||
valueFormatter?: (value: any) => string;
|
||||
};
|
||||
@@ -104,4 +104,11 @@ export interface IFilterOperator {
|
||||
value: TableFilter["operator"];
|
||||
label: string;
|
||||
secondaryLabel?: React.ReactNode;
|
||||
group?: string;
|
||||
}
|
||||
|
||||
export interface IFilterCustomInputProps {
|
||||
onChange: (value: any) => void;
|
||||
operator: TableFilter["operator"];
|
||||
[key: string]: any;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user