Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

manage named filters in application settings #1141

Merged
merged 2 commits into from
Jan 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading