Skip to content

Commit

Permalink
manage named filters in application settings (#1141)
Browse files Browse the repository at this point in the history
* manage named filters in application settings

* implement review suggestions, add etsts
  • Loading branch information
heswell authored Jan 24, 2024
1 parent 5b706db commit ddcf73a
Show file tree
Hide file tree
Showing 9 changed files with 309 additions and 149 deletions.
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
// TODO try and get TS path alias working to avoid relative paths like this
import { defaultPatternsByType, formatDate } from "@finos/vuu-utils";
import { DefaultFilterBar } from "../../../../../../showcase/src/examples/Filters/FilterBar/FilterBar.examples";
import {
DefaultFilterBar,
FilterBarMultipleFilters,
} from "../../../../../../showcase/src/examples/Filters/FilterBar/FilterBar.examples";

// Common selectors
const OVERFLOW_CONTAINER = ".vuuOverflowContainer-wrapContainer";
Expand Down Expand Up @@ -521,3 +524,45 @@ describe("WHEN a user applies a date filter", () => {
})
);
});

describe("Deleting and renaming filters", () => {
describe("WHEN user deletes a filter", () => {
it("THEN onFilterDeleted callback is called", () => {
const onFilterDeleted = cy.stub().as("onFilterDeleted");
cy.mount(<FilterBarMultipleFilters onFilterDeleted={onFilterDeleted} />);

findOverflowItem('[data-index="0"]').findByRole("button").realClick();
clickButton("Delete");
clickButton("Remove");

cy.get("@onFilterDeleted").should("be.calledWithExactly", {
column: "currency",
name: "Filter One",
op: "=",
value: "EUR",
});
});
});

describe("WHEN user renames a filter", () => {
it("THEN onFilterRenamed callback is called", () => {
const onFilterRenamed = cy.stub().as("onFilterRenamed");
cy.mount(<FilterBarMultipleFilters onFilterRenamed={onFilterRenamed} />);

findOverflowItem('[data-index="0"]').findByText("Filter One").dblclick();
cy.realType("Test");
cy.realPress("Enter");

cy.get("@onFilterRenamed").should(
"be.calledWithExactly",
{
column: "currency",
name: "Filter One",
op: "=",
value: "EUR",
},
"Test"
);
});
});
});
6 changes: 6 additions & 0 deletions vuu-ui/packages/vuu-filters/src/filter-bar/FilterBar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ export interface FilterBarProps extends HTMLAttributes<HTMLDivElement> {
filters: Filter[];
onApplyFilter: (filter: DataSourceFilter) => void;
onChangeActiveFilterIndex: ActiveItemChangeHandler;
onFilterDeleted?: (filter: Filter) => void;
onFilterRenamed?: (filter: Filter, name: string) => void;
onFiltersChanged?: (filters: Filter[]) => void;
showMenu?: boolean;
tableSchema: TableSchema;
Expand All @@ -37,6 +39,8 @@ export const FilterBar = ({
filters: filtersProp,
onApplyFilter,
onChangeActiveFilterIndex: onChangeActiveFilterIndexProp,
onFilterDeleted,
onFilterRenamed,
onFiltersChanged,
showMenu: showMenuProp = false,
tableSchema,
Expand Down Expand Up @@ -71,6 +75,8 @@ export const FilterBar = ({
onApplyFilter,
onChangeActiveFilterIndex: onChangeActiveFilterIndexProp,
onFiltersChanged,
onFilterDeleted,
onFilterRenamed,
showMenu: showMenuProp,
tableSchema,
});
Expand Down
11 changes: 1 addition & 10 deletions vuu-ui/packages/vuu-filters/src/filter-bar/FilterBarMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
import { PopupMenu } from "@finos/vuu-popups";
import { useFilterBarMenu } from "./useFilterBarMenu";

export const FilterBarMenu = () => {
const classBase = "vuuFilterBarMenu";

const { menuBuilder, menuActionHandler } = useFilterBarMenu();

return (
<div className={classBase}>
<PopupMenu
icon="tune"
menuBuilder={menuBuilder}
menuActionHandler={menuActionHandler}
tabIndex={-1}
/>
<PopupMenu icon="tune" menuLocation="filter-bar-menu" tabIndex={-1} />
</div>
);
};
9 changes: 7 additions & 2 deletions vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBar.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,8 @@ export interface FilterBarHookProps
| "filters"
| "onApplyFilter"
| "onChangeActiveFilterIndex"
| "onFilterDeleted"
| "onFilterRenamed"
| "onFiltersChanged"
| "showMenu"
| "tableSchema"
Expand All @@ -57,6 +59,8 @@ export const useFilterBar = ({
filters: filtersProp,
onApplyFilter,
onChangeActiveFilterIndex: onChangeActiveFilterIndexProp,
onFilterDeleted,
onFilterRenamed,
onFiltersChanged,
showMenu: showMenuProp,
tableSchema,
Expand Down Expand Up @@ -95,6 +99,8 @@ export const useFilterBar = ({
activeFilterIndex: activeFilterIdexProp,
applyFilter,
filters: filtersProp,
onFilterDeleted,
onFilterRenamed,
onFiltersChanged,
tableSchema,
});
Expand Down Expand Up @@ -162,7 +168,7 @@ export const useFilterBar = ({
}
});
},
[focusFilterPill, onDeleteFilter]
[filters.length, focusFilterPill, onDeleteFilter]
);

const getDeletePrompt = useMemo(
Expand Down Expand Up @@ -372,7 +378,6 @@ export const useFilterBar = ({

const handleKeyDownMenu = useCallback<KeyboardEventHandler>(
(evt) => {
console.log(`keydown from List ${evt.key}`);
const { current: container } = containerRef;
if (evt.key === "Backspace" && container) {
evt.preventDefault();
Expand Down
33 changes: 0 additions & 33 deletions vuu-ui/packages/vuu-filters/src/filter-bar/useFilterBarMenu.ts

This file was deleted.

104 changes: 12 additions & 92 deletions vuu-ui/packages/vuu-filters/src/filter-bar/useFilters.ts
Original file line number Diff line number Diff line change
@@ -1,99 +1,25 @@
import { useCallback } from "react";
import { TableSchema } from "@finos/vuu-data-types";
import { Filter, NamedFilter } from "@finos/vuu-filter-types";
import { useLayoutManager } from "@finos/vuu-shell";
import { Filter } from "@finos/vuu-filter-types";
import { FilterStateHookProps, useFilterState } from "./useFilterState";

export interface FiltersHookProps extends FilterStateHookProps {
onFilterDeleted?: (filter: Filter) => void;
onFilterRenamed?: (filter: Filter, name: string) => void;
onFiltersChanged?: (filters: Filter[]) => void;
tableSchema?: TableSchema;
}

export const useFilters = ({
onFilterDeleted,
onFilterRenamed,
onFiltersChanged,
tableSchema,
...filterStateHookProps
}: FiltersHookProps) => {
const { getApplicationSettings, saveApplicationSettings } =
useLayoutManager();
const { filterState, onFilterStateChange, onActiveIndicesChange } =
useFilterState(filterStateHookProps);

const saveFilterToSettings = useCallback(
(filter: Filter, name?: string) => {
if (tableSchema && name) {
const savedFilters = getApplicationSettings(
"filters"
) as SavedFilterMap;
let newFilters = savedFilters;
const { module, table } = tableSchema.table;
const key = `${module}:${table}`;
if (savedFilters) {
if (savedFilters[key]) {
if (hasFilterWithName(savedFilters[key], name)) {
newFilters = {
...savedFilters,
[key]: savedFilters[key].map((f) =>
f.name === name ? { ...filter, name } : f
),
};
} else if (
filter?.name &&
filter?.name !== name &&
hasFilterWithName(savedFilters[key], filter.name)
) {
newFilters = {
...savedFilters,
[key]: savedFilters[key].map((f) =>
f.name === filter.name ? { ...filter, name } : f
),
};
} else {
newFilters = {
...savedFilters,
[key]: savedFilters[key].concat({ ...filter, name }),
};
}
} else {
newFilters = {
...savedFilters,
[key]: [{ ...filter, name }],
};
}
} else {
newFilters = {
[key]: [{ ...filter, name }],
};
}
if (newFilters !== savedFilters) {
saveApplicationSettings(newFilters, "filters");
}
}
},
[getApplicationSettings, saveApplicationSettings, tableSchema]
);

const removeFilterFromSettings = useCallback(
(filter: Filter | NamedFilter) => {
if (!tableSchema || !filter.name) return;

const savedFilters = getApplicationSettings("filters") as SavedFilterMap;
if (!savedFilters) return;

const { module, table } = tableSchema.table;
const key = `${module}:${table}`;

if (hasFilterWithName(savedFilters[key], filter.name)) {
const newSavedFilters = {
...savedFilters,
[key]: savedFilters[key].filter((f) => f.name !== filter.name),
};
saveApplicationSettings(newSavedFilters, "filters");
}
},
[getApplicationSettings, saveApplicationSettings, tableSchema]
);

const handleAddFilter = useCallback(
(filter: Filter) => {
const index = filterState.filters.length;
Expand Down Expand Up @@ -125,14 +51,15 @@ export const useFilters = ({

onFilterStateChange({ filters: newFilters, activeIndices: newIndices });
onFiltersChanged?.(newFilters);
removeFilterFromSettings(filter);
onFilterDeleted?.(filter);
return index;
},
[
filterState,
onFiltersChanged,
filterState.filters,
filterState.activeIndices,
onFilterStateChange,
removeFilterFromSettings,
onFiltersChanged,
onFilterDeleted,
]
);

Expand All @@ -149,11 +76,11 @@ export const useFilters = ({
});
onFilterStateChange({ ...filterState, filters: newFilters });
onFiltersChanged?.(newFilters);
saveFilterToSettings(filter, name);
onFilterRenamed?.(filter, name);

return index;
},
[filterState, onFiltersChanged, onFilterStateChange, saveFilterToSettings]
[filterState, onFilterStateChange, onFiltersChanged, onFilterRenamed]
);

const handleChangeFilter = useCallback(
Expand Down Expand Up @@ -186,13 +113,6 @@ export const useFilters = ({
};
};

type SavedFilterMap = {
[key: string]: NamedFilter[];
};

const hasFilterWithName = (filters: NamedFilter[], name: string) =>
filters.findIndex((f) => f.name === name) !== -1;

const appendIfNotPresent = (ns: number[], n: number) =>
ns.includes(n) ? ns : ns.concat(n);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,16 @@ export interface FilterTableFeatureProps {

const VuuFilterTableFeature = ({ tableSchema }: FilterTableFeatureProps) => {
const {
buildViewserverMenuOptions,
buildFilterTableMenuOptions,
filterBarProps,
handleMenuAction,
handleFilterTableMenuAction,
tableProps,
} = useFilterTable({ tableSchema });

return (
<ContextMenuProvider
menuActionHandler={handleMenuAction}
menuBuilder={buildViewserverMenuOptions}
menuActionHandler={handleFilterTableMenuAction}
menuBuilder={buildFilterTableMenuOptions}
>
<FlexboxLayout
className={classBase}
Expand Down
Loading

0 comments on commit ddcf73a

Please sign in to comment.