Skip to content

Commit

Permalink
feat: allow retaining args when filter is changed
Browse files Browse the repository at this point in the history
  • Loading branch information
lawvs committed Aug 10, 2024
1 parent 311f306 commit 0ce4129
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 18 deletions.
5 changes: 5 additions & 0 deletions .changeset/hip-pumas-build.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@fn-sphere/filter": patch
---

Add `tryRetainArgs` to allow retaining `args` when filter is changed
61 changes: 47 additions & 14 deletions packages/filter/src/hooks/use-filter-select.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,36 @@
import {
isEqualPath,
isSameType,
type FilterField,
type SingleFilter,
type StandardFnSchema,
} from "@fn-sphere/core";
import { useFilterRule } from "./use-filter-rule.js";
import { useFilterSchemaContext } from "./use-filter-schema-context.js";

export type UpdateFieldOptions = {
export interface UpdateFilterOptions {
/**
* Try to continue using the current filter when the field is changed.
* Try to continue using the current args when the field is changed.
*
* @default true
*/
tryRetainFilter?: boolean;
tryRetainArgs?: boolean;
}

export interface UpdateFieldOptions extends UpdateFilterOptions {
/**
* Automatically select the first filter when the field is changed and the filter is not retained.
* Try to continue using the current filter when the field is changed.
*
* @default true
*/
autoSelectFirstFilter?: boolean;
tryRetainFilter?: boolean;
/**
* Try to continue using the current args when the field is changed.
* Automatically select the first filter when the field is changed and the filter is not retained.
*
* @default true
*/
tryRetainArgs?: boolean;
};
autoSelectFirstFilter?: boolean;
}

export const useFilterSelect = (rule: SingleFilter) => {
const {
Expand Down Expand Up @@ -67,6 +71,28 @@ export const useFilterSelect = (rule: SingleFilter) => {
value: filter,
}));

/**
* Checks if the new filter schema has the same arguments as the current filter schema.
*/
const canRetainArgs = (newFilterSchema: StandardFnSchema) => {
if (!selectedField) {
// This should not happen since the field should be selected before the filter
console.error("Field not found", rule);
return false;
}
const currentFilterSchema = selectedField.filterFnList.find(
(filter) => filter.name === rule.name,
);
if (!currentFilterSchema) {
// Select filter first time
return false;
}
return isSameType(
newFilterSchema.define.parameters(),
currentFilterSchema.define.parameters(),
);
};

const updateField = (
newField: FilterField,
{
Expand All @@ -79,7 +105,7 @@ export const useFilterSelect = (rule: SingleFilter) => {
console.error("Field has no filter", newField);
throw new Error("Field has no filter");
}
// Retain filter when possible
// If new field has the same filter, it can be retained
const canRetainFilter = newField.filterFnList.some(
(filter) => filter.name === rule.name,
);
Expand All @@ -88,13 +114,16 @@ export const useFilterSelect = (rule: SingleFilter) => {
? newField.filterFnList[0].name
: undefined;

// TODO check if the arguments are matched new filter when autoSelectFirstFilter enabled
const needRetainArgs = tryRetainArgs && needRetainFilter;
const newFilterSchema = needRetainFilter ? rule.name : fallbackFilter;

const needRetainArgs =
tryRetainArgs &&
(needRetainFilter || canRetainArgs(newField.filterFnList[0]));

updateRule({
...rule,
path: newField.path,
name: needRetainFilter ? rule.name : fallbackFilter,
name: newFilterSchema,
// If the filter is retained, keep the arguments
args: needRetainArgs
? rule.args
Expand All @@ -103,11 +132,15 @@ export const useFilterSelect = (rule: SingleFilter) => {
});
};

const updateFilter = (filterSchema: StandardFnSchema) => {
const updateFilter = (
filterSchema: StandardFnSchema,
{ tryRetainArgs = true }: UpdateFilterOptions = {},
) => {
const needRetainArgs = tryRetainArgs && canRetainArgs(filterSchema);
updateRule({
...rule,
name: filterSchema.name,
args: [],
args: needRetainArgs ? rule.args : [],
});
};

Expand Down
14 changes: 10 additions & 4 deletions packages/filter/src/views/filter-select.tsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,18 @@
import type { SingleFilter } from "@fn-sphere/core";
import { useFilterSelect } from "../hooks/use-filter-select.js";
import {
useFilterSelect,
type UpdateFilterOptions,
} from "../hooks/use-filter-select.js";
import { useView } from "../theme/index.js";

export type FilterSelectProps = {
rule: SingleFilter;
};
} & UpdateFilterOptions;

export const FilterSelect = ({ rule }: FilterSelectProps) => {
export const FilterSelect = ({
rule,
...updateFilterOptions
}: FilterSelectProps) => {
const { Select: SelectView } = useView("components");
const { selectedField, selectedFilter, filterOptions, updateFilter } =
useFilterSelect(rule);
Expand All @@ -16,7 +22,7 @@ export const FilterSelect = ({ rule }: FilterSelectProps) => {
value={selectedFilter}
disabled={!selectedField}
options={filterOptions}
onChange={updateFilter}
onChange={(val) => updateFilter(val, updateFilterOptions)}
/>
);
};
Expand Down

0 comments on commit 0ce4129

Please sign in to comment.