Skip to content

Commit

Permalink
refactor: update type of advanced filter
Browse files Browse the repository at this point in the history
  • Loading branch information
lawvs committed Aug 3, 2024
1 parent d6f2029 commit 257136b
Show file tree
Hide file tree
Showing 5 changed files with 91 additions and 73 deletions.
2 changes: 1 addition & 1 deletion packages/playground/src/app.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ export const App = () => {
const { rule, predicate, openFilterDialog } = useAdvancedFilter({
storageKey: "fn-sphere-flatten-filter",
schema: presetSchema,
filterList: dataFilters,
filterFnList: dataFilters,
fieldDeepLimit: Infinity,
dialogProps: {
width: "600px",
Expand Down
47 changes: 21 additions & 26 deletions packages/playground/src/filter/create-advanced-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
createSingleFilter,
defaultMapFieldName,
defaultMapFilterName,
type BasicFilterBuilderProps,
type BasicFilterSphereInput,
} from "@fn-sphere/filter";
import { createElement } from "react";
import { createRoot } from "react-dom/client";
Expand All @@ -20,7 +20,7 @@ import {
} from "./flatten-filter-dialog.js";

type OpenFilterProps<Data = unknown> = {
filterBuilder: BasicFilterBuilderProps<Data> & {
filterBuilder: BasicFilterSphereInput<Data> & {
// uncontrolled mode only for the dialog
defaultRule: FilterGroup | undefined;
};
Expand All @@ -29,26 +29,21 @@ type OpenFilterProps<Data = unknown> = {
abortSignal?: AbortSignal;
};

// See https://stackoverflow.com/questions/43159887/make-a-single-property-optional-in-typescript
type PartialBy<T, K extends keyof T> = Pick<Partial<T>, K> & Omit<T, K>;

export type CreateAdvancedFilterProps<Data = unknown> = PartialBy<
BasicFilterBuilderProps<Data>,
"filterList"
> & {
defaultRule?: FilterGroup | undefined;
/**
*
* Set `null` to disable storage.
*
* The default storage implementation uses `localStorage` for storage/retrieval, `JSON.stringify()`/`JSON.parse()` for serialization/deserialization.
*
* @default null
*/
storageKey?: string | null;
dialogProps?: OpenFilterProps<Data>["dialogProps"];
container?: OpenFilterProps<Data>["container"];
};
export type CreateAdvancedFilterProps<Data = unknown> =
BasicFilterSphereInput<Data> & {
defaultRule?: FilterGroup | undefined;
/**
*
* Set `null` to disable storage.
*
* The default storage implementation uses `localStorage` for storage/retrieval, `JSON.stringify()`/`JSON.parse()` for serialization/deserialization.
*
* @default null
*/
storageKey?: string | null;
dialogProps?: OpenFilterProps<Data>["dialogProps"];
container?: OpenFilterProps<Data>["container"];
};

export const openFlattenFilterDialog = async <Data>(
options: OpenFilterProps<Data>,
Expand Down Expand Up @@ -110,7 +105,7 @@ export const openFlattenFilterDialog = async <Data>(

export const defaultOptions = {
schema: z.any(),
filterList: presetFilter,
filterFnList: presetFilter,
fieldDeepLimit: 1,
mapFieldName: defaultMapFieldName,
mapFilterName: defaultMapFilterName,
Expand Down Expand Up @@ -157,8 +152,8 @@ export const createAdvancedFilter = <Data>(
const rule = await getRule();
const predicate = createFilterPredicate({
schema: options.schema,
filterList: options.filterList,
rule,
filterFnList: options.filterFnList,
filterRule: rule,
});
return predicate;
};
Expand All @@ -175,7 +170,7 @@ export const createAdvancedFilter = <Data>(
const result = await openFlattenFilterDialog({
filterBuilder: {
schema: options.schema,
filterList: options.filterList,
filterFnList: options.filterFnList,
fieldDeepLimit: options.fieldDeepLimit,
mapFieldName: options.mapFieldName,
mapFilterName: options.mapFilterName,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,50 @@
import { countNumberOfRules } from "@fn-sphere/core";
import { Fragment } from "react";
import { FilterSchemaProvider } from "./hooks/use-filter-schema-context.js";
import { useView } from "./theme/index.js";
import type { BasicFilterSphereInput } from "./types.js";
import { countNumberOfRules, type FilterId } from "@fn-sphere/core";
import type {
BasicFilterSphereInput,
FilterGroup,
SingleFilter,
} from "@fn-sphere/filter";
import {
createFilterGroup,
createSingleFilter,
defaultMapFieldName,
defaultMapFilterName,
isFlattenFilterGroup,
} from "./utils.js";
FilterSchemaProvider,
useFilterSphere,
useView,
} from "@fn-sphere/filter";
import { Fragment } from "react";

interface FlattenFilterBuilderProps<Data = unknown>
extends BasicFilterSphereInput<Data> {
filterRule?: FilterGroup;
onRuleChange?: (rule: FilterGroup) => void;
}

type FilterBuilderProps<Data = unknown> = BasicFilterSphereInput<Data>;
export type FlattenFilterGroup = {
id: FilterId;
type: "FilterGroup";
op: "or";
conditions: {
id: FilterId;
type: "FilterGroup";
op: "and";
conditions: SingleFilter[];
}[];
};

const isFlattenFilterGroup = (
filterGroup: FilterGroup,
): filterGroup is FlattenFilterGroup => {
if (filterGroup.op === "and") {
return false;
}

return filterGroup.conditions.every(
(group) =>
group.type === "FilterGroup" &&
group.op === "and" &&
group.conditions.every((rule) => rule.type === "Filter"),
);
};

const createFlattenFilterGroup = () =>
createFilterGroup({
Expand All @@ -25,14 +58,13 @@ const createFlattenFilterGroup = () =>
});

export const FlattenFilterBuilder = <Data,>({
schema,
filterList,
filterRule: filterGroup = createFlattenFilterGroup(),
fieldDeepLimit = 1,
mapFieldName = defaultMapFieldName,
mapFilterName = defaultMapFilterName,
onRuleChange,
}: FilterBuilderProps<Data>) => {
...props
}: FlattenFilterBuilderProps<Data>) => {
const { context } = useFilterSphere({
ruleValue: filterGroup,
...props,
});
const {
RuleJoiner,
FilterGroupContainer,
Expand All @@ -47,7 +79,7 @@ export const FlattenFilterBuilder = <Data,>({
<div>Invalid Rule</div>
<ButtonView
onClick={() => {
onRuleChange?.(createFlattenFilterGroup());
props.onRuleChange?.(createFlattenFilterGroup());
}}
>
Reset Filter
Expand All @@ -62,7 +94,7 @@ export const FlattenFilterBuilder = <Data,>({
<FilterGroupContainer isRoot filterGroup={filterGroup}>
<ButtonView
onClick={() => {
onRuleChange?.(createFlattenFilterGroup());
props.onRuleChange?.(createFlattenFilterGroup());
}}
>
Add Filter
Expand All @@ -72,18 +104,7 @@ export const FlattenFilterBuilder = <Data,>({
}

return (
<FilterSchemaProvider
value={{
schema,
filterList,
filterRule: filterGroup,
onRuleChange,

mapFieldName,
mapFilterName,
fieldDeepLimit,
}}
>
<FilterSchemaProvider value={context}>
<FilterGroupContainer isRoot filterGroup={filterGroup}>
{filterGroup.conditions.map((andGroup, groupIdx) => {
return (
Expand Down
24 changes: 13 additions & 11 deletions packages/playground/src/filter/flatten-filter-dialog.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,19 @@ import {
import {
createFilterGroup,
createSingleFilter,
FlattenFilterBuilder,
type BasicFilterBuilderProps,
type BasicFilterSphereInput,
} from "@fn-sphere/filter";
import { useState } from "react";
import { Dialog, type DialogProps } from "tdesign-react";
import { FlattenFilterBuilder } from "./flatten-filter-builder";

type FilterValue<Data> = {
rule: FilterGroup;
predicate: (data: Data) => boolean;
};

export type FlattenFilterDialogProps<Data> = {
filterBuilder: BasicFilterBuilderProps<Data> & {
filterBuilder: BasicFilterSphereInput<Data> & {
rule?: FilterGroup;
defaultRule?: FilterGroup;
};
Expand Down Expand Up @@ -46,7 +46,9 @@ export const FlattenFilterDialog = <Data,>({
const controlled = filterBuilder.rule !== undefined;
// This state will be used only when the dialog is uncontrolled.
const [filterGroup, setFilterGroup] = useState(filterBuilder.defaultRule);
const filterList = filterBuilder.filterList ?? presetFilter;
const filterFnList = filterBuilder.filterFnList ?? presetFilter;
const realRule = controlled ? filterBuilder.rule : filterGroup;

return (
<Dialog
visible={open}
Expand All @@ -62,26 +64,26 @@ export const FlattenFilterDialog = <Data,>({
}),
predicate: createFilterPredicate({
schema: filterBuilder.schema,
filterList,
rule: filterGroup,
filterFnList,
filterRule: filterGroup,
}),
});
}}
>
<FlattenFilterBuilder
schema={filterBuilder.schema}
filterList={filterList}
filterFnList={filterFnList}
fieldDeepLimit={filterBuilder.fieldDeepLimit}
mapFieldName={filterBuilder.mapFieldName}
mapFilterName={filterBuilder.mapFilterName}
rule={controlled ? filterBuilder.rule : filterGroup}
onChange={(newRule) => {
filterRule={realRule}
onRuleChange={(newRule) => {
onRuleChange?.({
rule: newRule,
predicate: createFilterPredicate({
schema: filterBuilder.schema,
filterList,
rule: newRule,
filterFnList,
filterRule: newRule,
}),
});
if (!controlled) {
Expand Down
8 changes: 4 additions & 4 deletions packages/playground/src/filter/use-advanced-filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ export type UseAdvancedFilterProps<Data = unknown> =
* ```tsx
* const { rule, predicate, openFilter } = useFilter({
* schema: schema,
* filterList: filterList,
* filterFnList: filterFnList,
* });
*
* await openFilter();
Expand Down Expand Up @@ -57,8 +57,8 @@ export const useAdvancedFilter = <Data>(
rule,
predicate: createFilterPredicate({
schema: options.schema,
filterList: options.filterList,
rule,
filterFnList: options.filterFnList,
filterRule: rule,
}),
openFilterDialog: async ({
abortSignal,
Expand All @@ -77,7 +77,7 @@ export const useAdvancedFilter = <Data>(
const data = await openFlattenFilterDialog({
filterBuilder: {
schema: options.schema,
filterList: options.filterList,
filterFnList: options.filterFnList,
fieldDeepLimit: options.fieldDeepLimit,
defaultRule: rule,
},
Expand Down

0 comments on commit 257136b

Please sign in to comment.