@databiosphere/findable-ui 43.0.0 → 44.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +14 -0
- package/lib/common/filters/sort/config/types.d.ts +13 -0
- package/lib/common/filters/sort/config/types.js +8 -0
- package/lib/common/filters/sort/config/utils.d.ts +8 -0
- package/lib/common/filters/sort/config/utils.js +9 -0
- package/lib/common/filters/sort/models/utils.d.ts +23 -0
- package/lib/common/filters/sort/models/utils.js +41 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.js +6 -1
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.d.ts +3 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.js +8 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.d.ts +6 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.js +1 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.d.ts +14 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.js +23 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.d.ts +2 -0
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.d.ts +3 -1
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.js +24 -16
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/constants.d.ts +5 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/constants.js +17 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.d.ts +2 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.js +28 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.d.ts +9 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.js +25 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.d.ts +6 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.js +9 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/types.d.ts +6 -0
- package/lib/components/Filter/components/controls/Controls/components/FilterSort/types.js +1 -0
- package/lib/components/Filter/components/controls/Controls/controls.d.ts +2 -3
- package/lib/components/Filter/components/controls/Controls/controls.js +4 -2
- package/lib/components/Filter/components/controls/Controls/controls.styles.js +2 -1
- package/lib/components/Filter/components/controls/Controls/types.d.ts +6 -0
- package/lib/components/Filter/components/controls/Controls/types.js +1 -0
- package/lib/components/Filter/components/surfaces/types.d.ts +3 -1
- package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.js +2 -2
- package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.d.ts +0 -7
- package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.js +0 -11
- package/lib/config/entities.d.ts +2 -0
- package/lib/hooks/useCategoryFilter.d.ts +4 -9
- package/lib/hooks/useCategoryFilter.js +5 -15
- package/lib/providers/exploreState/actions/updateFilterSort/action.d.ts +10 -0
- package/lib/providers/exploreState/actions/updateFilterSort/action.js +21 -0
- package/lib/providers/exploreState/actions/updateFilterSort/dispatch.d.ts +7 -0
- package/lib/providers/exploreState/actions/updateFilterSort/dispatch.js +12 -0
- package/lib/providers/exploreState/actions/updateFilterSort/types.d.ts +7 -0
- package/lib/providers/exploreState/actions/updateFilterSort/types.js +1 -0
- package/lib/providers/exploreState/actions/updateFilterSort/utils.d.ts +10 -0
- package/lib/providers/exploreState/actions/updateFilterSort/utils.js +22 -0
- package/lib/providers/exploreState/initializer/constants.js +2 -0
- package/lib/providers/exploreState/initializer/utils.js +2 -0
- package/lib/providers/exploreState.d.ts +5 -1
- package/lib/providers/exploreState.js +9 -1
- package/lib/tests/testIds.d.ts +2 -0
- package/lib/tests/testIds.js +2 -0
- package/lib/views/ExploreView/exploreView.js +7 -1
- package/lib/views/ExploreView/hooks/UseUpdateFilterSort/hook.d.ts +2 -0
- package/lib/views/ExploreView/hooks/UseUpdateFilterSort/hook.js +12 -0
- package/lib/views/ExploreView/hooks/UseUpdateFilterSort/types.d.ts +6 -0
- package/lib/views/ExploreView/hooks/UseUpdateFilterSort/types.js +1 -0
- package/package.json +1 -1
- package/src/common/filters/sort/config/types.ts +14 -0
- package/src/common/filters/sort/config/utils.ts +11 -0
- package/src/common/filters/sort/models/utils.ts +57 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.tsx +11 -1
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.ts +22 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.ts +7 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.ts +33 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.ts +2 -0
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.ts +36 -13
- package/src/components/Filter/components/controls/Controls/components/FilterSort/constants.ts +22 -0
- package/src/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.ts +34 -0
- package/src/components/Filter/components/controls/Controls/components/FilterSort/filterSort.tsx +73 -0
- package/src/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.tsx +15 -0
- package/src/components/Filter/components/controls/Controls/components/FilterSort/types.ts +7 -0
- package/src/components/Filter/components/controls/Controls/controls.styles.ts +2 -1
- package/src/components/Filter/components/controls/Controls/controls.tsx +11 -3
- package/src/components/Filter/components/controls/Controls/types.ts +10 -0
- package/src/components/Filter/components/surfaces/types.ts +3 -1
- package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.ts +2 -2
- package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.ts +0 -15
- package/src/config/entities.ts +2 -0
- package/src/hooks/useCategoryFilter.ts +8 -19
- package/src/providers/exploreState/actions/updateFilterSort/action.ts +30 -0
- package/src/providers/exploreState/actions/updateFilterSort/dispatch.ts +16 -0
- package/src/providers/exploreState/actions/updateFilterSort/types.ts +9 -0
- package/src/providers/exploreState/actions/updateFilterSort/utils.ts +30 -0
- package/src/providers/exploreState/initializer/constants.ts +2 -0
- package/src/providers/exploreState/initializer/utils.ts +2 -0
- package/src/providers/exploreState.tsx +14 -1
- package/src/tests/testIds.ts +2 -0
- package/src/views/ExploreView/exploreView.tsx +16 -1
- package/src/views/ExploreView/hooks/UseUpdateFilterSort/hook.ts +20 -0
- package/src/views/ExploreView/hooks/UseUpdateFilterSort/types.ts +7 -0
- package/tests/buildCategoryViews.test.ts +282 -0
- package/tests/filterSortUtils.test.ts +180 -0
- package/tests/getFilterSortType.test.ts +45 -0
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [44.0.0](https://github.com/DataBiosphere/findable-ui/compare/v43.0.0...v44.0.0) (2025-08-28)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* configure default filter sort ([#640](https://github.com/DataBiosphere/findable-ui/issues/640)) (#643)
|
|
9
|
+
|
|
10
|
+
### Features
|
|
11
|
+
|
|
12
|
+
* configure default filter sort ([#640](https://github.com/DataBiosphere/findable-ui/issues/640)) ([#643](https://github.com/DataBiosphere/findable-ui/issues/643)) ([63be8d1](https://github.com/DataBiosphere/findable-ui/commit/63be8d1bb87e3a473385bd45f5196d1125cfb5ed))
|
|
13
|
+
* configure filter sort for tanstack column filtering ([#647](https://github.com/DataBiosphere/findable-ui/issues/647)) ([#648](https://github.com/DataBiosphere/findable-ui/issues/648)) ([c653a19](https://github.com/DataBiosphere/findable-ui/commit/c653a19ec4abd19a7aceafee6414d46f381c7544))
|
|
14
|
+
* create filter sort component ([#641](https://github.com/DataBiosphere/findable-ui/issues/641)) ([#644](https://github.com/DataBiosphere/findable-ui/issues/644)) ([7f80b7c](https://github.com/DataBiosphere/findable-ui/commit/7f80b7c2b76224cc3d6da7a435b678567bbb41c9))
|
|
15
|
+
* update filter sort ([#642](https://github.com/DataBiosphere/findable-ui/issues/642)) ([#645](https://github.com/DataBiosphere/findable-ui/issues/645)) ([e7470b5](https://github.com/DataBiosphere/findable-ui/commit/e7470b50d2c19e674c73e1de533559e2032516e6))
|
|
16
|
+
|
|
3
17
|
## [43.0.0](https://github.com/DataBiosphere/findable-ui/compare/v42.1.0...v43.0.0) (2025-08-19)
|
|
4
18
|
|
|
5
19
|
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { SiteConfig } from "../../../../config/entities";
|
|
2
|
+
import { FILTER_SORT } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the default filter sort type "ALPHA" or "COUNT" from config or ALPHA as fallback.
|
|
5
|
+
* @param config - Filter sort configuration.
|
|
6
|
+
* @returns default filter sort type.
|
|
7
|
+
*/
|
|
8
|
+
export declare function getFilterSortType(config?: SiteConfig): FILTER_SORT;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FILTER_SORT } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the default filter sort type "ALPHA" or "COUNT" from config or ALPHA as fallback.
|
|
4
|
+
* @param config - Filter sort configuration.
|
|
5
|
+
* @returns default filter sort type.
|
|
6
|
+
*/
|
|
7
|
+
export function getFilterSortType(config) {
|
|
8
|
+
return config?.filterSort?.sortBy ?? FILTER_SORT.ALPHA;
|
|
9
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { SelectCategoryValueView } from "../../../entities";
|
|
2
|
+
import { FILTER_SORT } from "../config/types";
|
|
3
|
+
/**
|
|
4
|
+
* Sort category value views based on filter sort configuration.
|
|
5
|
+
* Uses function selection pattern for efficiency.
|
|
6
|
+
* @param categoryValueViews - Array of category value views to sort.
|
|
7
|
+
* @param filterSort - Sort configuration (ALPHA or COUNT).
|
|
8
|
+
*/
|
|
9
|
+
export declare function sortCategoryValueViews(categoryValueViews: SelectCategoryValueView[], filterSort: FILTER_SORT): void;
|
|
10
|
+
/**
|
|
11
|
+
* Sort category value views alphabetically.
|
|
12
|
+
* @param cvv0 - First category value view to compare.
|
|
13
|
+
* @param cvv1 - Second category value view to compare.
|
|
14
|
+
* @returns Number indicating sort precedence of cvv0 vs cvv1.
|
|
15
|
+
*/
|
|
16
|
+
export declare function sortCategoryValueViewsAlpha(cvv0: SelectCategoryValueView, cvv1: SelectCategoryValueView): number;
|
|
17
|
+
/**
|
|
18
|
+
* Sort category value views by count (descending), then alphabetically.
|
|
19
|
+
* @param cvv0 - First category value view to compare.
|
|
20
|
+
* @param cvv1 - Second category value view to compare.
|
|
21
|
+
* @returns Number indicating sort precedence of cvv0 vs cvv1.
|
|
22
|
+
*/
|
|
23
|
+
export declare function sortCategoryValueViewsCount(cvv0: SelectCategoryValueView, cvv1: SelectCategoryValueView): number;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { COLLATOR_CASE_INSENSITIVE } from "../../../constants";
|
|
2
|
+
import { FILTER_SORT } from "../config/types";
|
|
3
|
+
/**
|
|
4
|
+
* Sort category value views based on filter sort configuration.
|
|
5
|
+
* Uses function selection pattern for efficiency.
|
|
6
|
+
* @param categoryValueViews - Array of category value views to sort.
|
|
7
|
+
* @param filterSort - Sort configuration (ALPHA or COUNT).
|
|
8
|
+
*/
|
|
9
|
+
export function sortCategoryValueViews(categoryValueViews, filterSort) {
|
|
10
|
+
const sortFn = filterSort === FILTER_SORT.ALPHA
|
|
11
|
+
? sortCategoryValueViewsAlpha
|
|
12
|
+
: sortCategoryValueViewsCount;
|
|
13
|
+
categoryValueViews.sort(sortFn);
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Sort category value views alphabetically.
|
|
17
|
+
* @param cvv0 - First category value view to compare.
|
|
18
|
+
* @param cvv1 - Second category value view to compare.
|
|
19
|
+
* @returns Number indicating sort precedence of cvv0 vs cvv1.
|
|
20
|
+
*/
|
|
21
|
+
export function sortCategoryValueViewsAlpha(cvv0, cvv1) {
|
|
22
|
+
// Handle empty labels.
|
|
23
|
+
if (!cvv0.label)
|
|
24
|
+
return 1;
|
|
25
|
+
if (!cvv1.label)
|
|
26
|
+
return -1;
|
|
27
|
+
return COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Sort category value views by count (descending), then alphabetically.
|
|
31
|
+
* @param cvv0 - First category value view to compare.
|
|
32
|
+
* @param cvv1 - Second category value view to compare.
|
|
33
|
+
* @returns Number indicating sort precedence of cvv0 vs cvv1.
|
|
34
|
+
*/
|
|
35
|
+
export function sortCategoryValueViewsCount(cvv0, cvv1) {
|
|
36
|
+
// Sort by count descending, then alphabetically.
|
|
37
|
+
const countDiff = cvv1.count - cvv0.count;
|
|
38
|
+
if (countDiff !== 0)
|
|
39
|
+
return countDiff;
|
|
40
|
+
return sortCategoryValueViewsAlpha(cvv0, cvv1);
|
|
41
|
+
}
|
|
@@ -2,9 +2,11 @@ import { useCallback } from "react";
|
|
|
2
2
|
import { VIEW_KIND } from "../../../../../../common/categories/views/types";
|
|
3
3
|
import { CLEAR_ALL, } from "../../../../../../common/entities";
|
|
4
4
|
import { updater } from "../../../../../Table/components/TableFeatures/ColumnFilter/utils";
|
|
5
|
+
import { useUpdateFilterSort } from "./hooks/UseUpdateFilterSort/hook";
|
|
5
6
|
import { buildColumnFilters, getColumnFiltersCount } from "./utils";
|
|
6
7
|
export const ColumnFiltersAdapter = ({ renderSurface, table, }) => {
|
|
7
|
-
const
|
|
8
|
+
const { enabled: filterSortEnabled, filterSort, onFilterSortChange, } = useUpdateFilterSort(table);
|
|
9
|
+
const categoryFilters = buildColumnFilters(table, filterSort);
|
|
8
10
|
const count = getColumnFiltersCount(table);
|
|
9
11
|
const onFilter = useCallback((categoryKey, selectedCategoryValue,
|
|
10
12
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars -- `selected` is not required by TanStack adapter.
|
|
@@ -28,6 +30,9 @@ export const ColumnFiltersAdapter = ({ renderSurface, table, }) => {
|
|
|
28
30
|
return renderSurface({
|
|
29
31
|
categoryFilters,
|
|
30
32
|
count,
|
|
33
|
+
filterSort,
|
|
34
|
+
filterSortEnabled,
|
|
31
35
|
onFilter,
|
|
36
|
+
onFilterSortChange,
|
|
32
37
|
});
|
|
33
38
|
};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useCallback, useMemo, useState } from "react";
|
|
2
|
+
import { initFilterSort, isFilterSortEnabled } from "./utils";
|
|
3
|
+
export const useUpdateFilterSort = (table) => {
|
|
4
|
+
const [filterSort, setFilterSort] = useState(initFilterSort(table));
|
|
5
|
+
const enabled = useMemo(() => isFilterSortEnabled(table), [table]);
|
|
6
|
+
const onFilterSortChange = useCallback((value) => setFilterSort(value), []);
|
|
7
|
+
return { enabled, filterSort, onFilterSortChange };
|
|
8
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { RowData, Table } from "@tanstack/react-table";
|
|
2
|
+
import { FILTER_SORT } from "../../../../../../../../common/filters/sort/config/types";
|
|
3
|
+
/**
|
|
4
|
+
* Returns the default filter sort type "ALPHA" or "COUNT" from table meta or ALPHA as fallback.
|
|
5
|
+
* @param table - Table.
|
|
6
|
+
* @returns default filter sort type.
|
|
7
|
+
*/
|
|
8
|
+
export declare function initFilterSort<T extends RowData>(table: Table<T>): FILTER_SORT;
|
|
9
|
+
/**
|
|
10
|
+
* Returns true if filter sort is enabled.
|
|
11
|
+
* @param table - Table.
|
|
12
|
+
* @returns true if filter sort is enabled.
|
|
13
|
+
*/
|
|
14
|
+
export declare function isFilterSortEnabled<T extends RowData>(table: Table<T>): boolean;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { FILTER_SORT } from "../../../../../../../../common/filters/sort/config/types";
|
|
2
|
+
/**
|
|
3
|
+
* Returns the default filter sort type "ALPHA" or "COUNT" from table meta or ALPHA as fallback.
|
|
4
|
+
* @param table - Table.
|
|
5
|
+
* @returns default filter sort type.
|
|
6
|
+
*/
|
|
7
|
+
export function initFilterSort(table) {
|
|
8
|
+
const { options } = table;
|
|
9
|
+
const { meta = {} } = options;
|
|
10
|
+
const { filterSort } = meta;
|
|
11
|
+
return filterSort || FILTER_SORT.ALPHA;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Returns true if filter sort is enabled.
|
|
15
|
+
* @param table - Table.
|
|
16
|
+
* @returns true if filter sort is enabled.
|
|
17
|
+
*/
|
|
18
|
+
export function isFilterSortEnabled(table) {
|
|
19
|
+
const { options } = table;
|
|
20
|
+
const { meta = {} } = options;
|
|
21
|
+
const { filterSort } = meta;
|
|
22
|
+
return Boolean(filterSort);
|
|
23
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RowData, Table, TableMeta as TanStackTableMeta } from "@tanstack/react-table";
|
|
2
|
+
import { FILTER_SORT } from "../../../../../../common/filters/sort/config/types";
|
|
2
3
|
import { CategoryGroup } from "../../../../../../config/entities";
|
|
3
4
|
import { SurfaceProps } from "../../../surfaces/types";
|
|
4
5
|
export interface ColumnFiltersAdapterProps<T extends RowData> {
|
|
@@ -7,4 +8,5 @@ export interface ColumnFiltersAdapterProps<T extends RowData> {
|
|
|
7
8
|
}
|
|
8
9
|
export interface ColumnFiltersTableMeta<T extends RowData> extends TanStackTableMeta<T> {
|
|
9
10
|
categoryGroups?: CategoryGroup[];
|
|
11
|
+
filterSort?: FILTER_SORT;
|
|
10
12
|
}
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { RowData, Table } from "@tanstack/react-table";
|
|
2
|
+
import { FILTER_SORT } from "../../../../../../common/filters/sort/config/types";
|
|
2
3
|
import { SurfaceProps } from "../../../surfaces/types";
|
|
3
4
|
/**
|
|
4
5
|
* Adapter for TanStack table column filters to category filters.
|
|
5
6
|
* @param table - Table.
|
|
7
|
+
* @param filterSort - Filter sort.
|
|
6
8
|
* @returns Category filters.
|
|
7
9
|
*/
|
|
8
|
-
export declare function buildColumnFilters<T extends RowData>(table: Table<T
|
|
10
|
+
export declare function buildColumnFilters<T extends RowData>(table: Table<T>, filterSort?: FILTER_SORT): SurfaceProps["categoryFilters"];
|
|
9
11
|
/**
|
|
10
12
|
* Adapter for TanStack table column filters to selected count.
|
|
11
13
|
* @param table - Table.
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { isRangeCategoryConfig } from "../../../../../../common/categories/config/range/typeGuards";
|
|
2
|
+
import { FILTER_SORT } from "../../../../../../common/filters/sort/config/types";
|
|
3
|
+
import { sortCategoryValueViews } from "../../../../../../common/filters/sort/models/utils";
|
|
2
4
|
import { getColumnHeader } from "../../../../../Table/common/utils";
|
|
3
|
-
import { getSortedFacetedValues } from "../../../../../Table/featureOptions/facetedColumn/utils";
|
|
4
5
|
/**
|
|
5
6
|
* Adapter for TanStack table to category configs.
|
|
6
7
|
* @param table - Table.
|
|
@@ -15,12 +16,13 @@ function buildCategoryConfigs(table) {
|
|
|
15
16
|
/**
|
|
16
17
|
* Adapter for TanStack table to category filters.
|
|
17
18
|
* @param table - Table.
|
|
19
|
+
* @param filterSort - Filter sort.
|
|
18
20
|
* @param categoryGroups - Category groups.
|
|
19
21
|
* @returns Category filters.
|
|
20
22
|
*/
|
|
21
|
-
function buildCategoryFilters(table, categoryGroups) {
|
|
23
|
+
function buildCategoryFilters(table, filterSort, categoryGroups) {
|
|
22
24
|
return categoryGroups.reduce((acc, categoryGroup) => {
|
|
23
|
-
const categoryFilter = mapCategoryFilter(table, categoryGroup);
|
|
25
|
+
const categoryFilter = mapCategoryFilter(table, filterSort, categoryGroup);
|
|
24
26
|
if (categoryFilter)
|
|
25
27
|
acc.push(categoryFilter);
|
|
26
28
|
return acc;
|
|
@@ -29,9 +31,10 @@ function buildCategoryFilters(table, categoryGroups) {
|
|
|
29
31
|
/**
|
|
30
32
|
* Adapter for TanStack table column filters to category filters.
|
|
31
33
|
* @param table - Table.
|
|
34
|
+
* @param filterSort - Filter sort.
|
|
32
35
|
* @returns Category filters.
|
|
33
36
|
*/
|
|
34
|
-
export function buildColumnFilters(table) {
|
|
37
|
+
export function buildColumnFilters(table, filterSort = FILTER_SORT.ALPHA) {
|
|
35
38
|
const { options } = table;
|
|
36
39
|
const { meta = {} } = options;
|
|
37
40
|
const { categoryGroups } = meta;
|
|
@@ -39,10 +42,12 @@ export function buildColumnFilters(table) {
|
|
|
39
42
|
// Build single category group with all (filterable) columns.
|
|
40
43
|
const categoryConfigs = buildCategoryConfigs(table);
|
|
41
44
|
// Build category filters from single category group.
|
|
42
|
-
return buildCategoryFilters(table,
|
|
45
|
+
return buildCategoryFilters(table, filterSort, [
|
|
46
|
+
{ categoryConfigs, label: "" },
|
|
47
|
+
]);
|
|
43
48
|
}
|
|
44
49
|
// Build category filters from category groups.
|
|
45
|
-
return buildCategoryFilters(table, categoryGroups);
|
|
50
|
+
return buildCategoryFilters(table, filterSort, categoryGroups);
|
|
46
51
|
}
|
|
47
52
|
/**
|
|
48
53
|
* Adapter for TanStack table column filters to selected count.
|
|
@@ -68,10 +73,11 @@ function mapCategoryConfig(column) {
|
|
|
68
73
|
/**
|
|
69
74
|
* Adapter for TanStack table to category filter.
|
|
70
75
|
* @param table - Table.
|
|
76
|
+
* @param filterSort - Filter sort.
|
|
71
77
|
* @param categoryGroup - Category group.
|
|
72
78
|
* @returns Category filter.
|
|
73
79
|
*/
|
|
74
|
-
function mapCategoryFilter(table, categoryGroup) {
|
|
80
|
+
function mapCategoryFilter(table, filterSort, categoryGroup) {
|
|
75
81
|
const { categoryConfigs, label } = categoryGroup;
|
|
76
82
|
const categoryViews = categoryConfigs.reduce((acc, categoryConfig) => {
|
|
77
83
|
const column = table.getColumn(categoryConfig.key);
|
|
@@ -86,7 +92,7 @@ function mapCategoryFilter(table, categoryGroup) {
|
|
|
86
92
|
}
|
|
87
93
|
else {
|
|
88
94
|
// Build select category view.
|
|
89
|
-
categoryView = mapColumnToSelectCategoryView(column, categoryConfig);
|
|
95
|
+
categoryView = mapColumnToSelectCategoryView(column, filterSort, categoryConfig);
|
|
90
96
|
}
|
|
91
97
|
return [...acc, categoryView];
|
|
92
98
|
}, []);
|
|
@@ -120,13 +126,14 @@ function mapColumnToRangeCategoryView(column, categoryConfig) {
|
|
|
120
126
|
/**
|
|
121
127
|
* Adapter for TanStack column to select category view.
|
|
122
128
|
* @param column - Column.
|
|
129
|
+
* @param filterSort - Filter sort.
|
|
123
130
|
* @param categoryConfig - Category config.
|
|
124
131
|
* @returns Select category view.
|
|
125
132
|
*/
|
|
126
|
-
function mapColumnToSelectCategoryView(column, categoryConfig) {
|
|
133
|
+
function mapColumnToSelectCategoryView(column, filterSort, categoryConfig) {
|
|
127
134
|
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
128
135
|
const isDisabled = facetedUniqueValues.size === 0;
|
|
129
|
-
const values = mapColumnToSelectCategoryValueView(column);
|
|
136
|
+
const values = mapColumnToSelectCategoryValueView(column, filterSort);
|
|
130
137
|
return {
|
|
131
138
|
annotation: undefined,
|
|
132
139
|
enableChartView: false,
|
|
@@ -140,23 +147,24 @@ function mapColumnToSelectCategoryView(column, categoryConfig) {
|
|
|
140
147
|
/**
|
|
141
148
|
* Adapter for TanStack column to select category value view.
|
|
142
149
|
* @param column - Column.
|
|
150
|
+
* @param filterSort - Filter sort.
|
|
143
151
|
* @returns Select category value view.
|
|
144
152
|
*/
|
|
145
|
-
function mapColumnToSelectCategoryValueView(column) {
|
|
153
|
+
function mapColumnToSelectCategoryValueView(column, filterSort) {
|
|
146
154
|
// Get the faceted unique values and sort them.
|
|
147
155
|
const facetedUniqueValues = column.getFacetedUniqueValues();
|
|
148
|
-
const sortedFacetsValues = getSortedFacetedValues(facetedUniqueValues);
|
|
149
156
|
// Selected values for the column.
|
|
150
157
|
const filterValue = (column.getFilterValue() || []);
|
|
151
158
|
// Build the select category values.
|
|
152
|
-
const
|
|
153
|
-
for (const [label, count] of
|
|
154
|
-
|
|
159
|
+
const categoryValueViews = [];
|
|
160
|
+
for (const [label, count] of [...facetedUniqueValues]) {
|
|
161
|
+
categoryValueViews.push({
|
|
155
162
|
count,
|
|
156
163
|
key: String(label),
|
|
157
164
|
label: String(label),
|
|
158
165
|
selected: filterValue.includes(label),
|
|
159
166
|
});
|
|
160
167
|
}
|
|
161
|
-
|
|
168
|
+
sortCategoryValueViews(categoryValueViews, filterSort);
|
|
169
|
+
return categoryValueViews;
|
|
162
170
|
}
|
package/lib/components/Filter/components/controls/Controls/components/FilterSort/constants.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { ListItemTextProps, MenuProps, SvgIconProps } from "@mui/material";
|
|
2
|
+
export declare const LIST_ITEM_BUTTON_TEXT_PROPS: ListItemTextProps;
|
|
3
|
+
export declare const LIST_ITEM_TEXT_PROPS: ListItemTextProps;
|
|
4
|
+
export declare const MENU_PROPS: Omit<MenuProps, "anchorEl" | "onClose" | "open">;
|
|
5
|
+
export declare const SVG_ICON_PROPS: SvgIconProps;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { SVG_ICON_PROPS as MUI_SVG_ICON_PROPS } from "../../../../../../../styles/common/mui/svgIcon";
|
|
2
|
+
import { TYPOGRAPHY_PROPS } from "../../../../../../../styles/common/mui/typography";
|
|
3
|
+
export const LIST_ITEM_BUTTON_TEXT_PROPS = {
|
|
4
|
+
slotProps: { primary: { variant: TYPOGRAPHY_PROPS.VARIANT.BODY_400 } },
|
|
5
|
+
};
|
|
6
|
+
export const LIST_ITEM_TEXT_PROPS = {
|
|
7
|
+
slotProps: { primary: { variant: TYPOGRAPHY_PROPS.VARIANT.BODY_500 } },
|
|
8
|
+
};
|
|
9
|
+
export const MENU_PROPS = {
|
|
10
|
+
anchorOrigin: { horizontal: "left", vertical: "bottom" },
|
|
11
|
+
marginThreshold: 8,
|
|
12
|
+
slotProps: { paper: { variant: "menu" } },
|
|
13
|
+
transformOrigin: { horizontal: "left", vertical: "top" },
|
|
14
|
+
};
|
|
15
|
+
export const SVG_ICON_PROPS = {
|
|
16
|
+
fontSize: MUI_SVG_ICON_PROPS.FONT_SIZE.SMALL,
|
|
17
|
+
};
|
package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.js
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { SettingsOutlined } from "@mui/icons-material";
|
|
2
|
+
import { ListItem, ListItemButton, ListItemText, Radio } from "@mui/material";
|
|
3
|
+
import React, { Fragment } from "react";
|
|
4
|
+
import { FILTER_SORT } from "../../../../../../../common/filters/sort/config/types";
|
|
5
|
+
import { ICON_BUTTON_PROPS } from "../../../../../../../styles/common/mui/iconButton";
|
|
6
|
+
import { TEST_IDS } from "../../../../../../../tests/testIds";
|
|
7
|
+
import { RadioCheckedIcon } from "../../../../../../common/CustomIcon/components/RadioCheckedIcon/radioCheckedIcon";
|
|
8
|
+
import { RadioUncheckedIcon } from "../../../../../../common/CustomIcon/components/RadioUncheckedIcon/radioUncheckedIcon";
|
|
9
|
+
import { useMenu } from "../../../../../../common/Menu/hooks/useMenu";
|
|
10
|
+
import { LIST_ITEM_BUTTON_TEXT_PROPS, LIST_ITEM_TEXT_PROPS, MENU_PROPS, SVG_ICON_PROPS, } from "./constants";
|
|
11
|
+
import { StyledIconButton, StyledMenu } from "./filterSort.styles";
|
|
12
|
+
export const FilterSort = ({ enabled = false, filterSort = FILTER_SORT.ALPHA, onFilterSortChange, }) => {
|
|
13
|
+
const { anchorEl, onClose, onOpen, open } = useMenu();
|
|
14
|
+
if (!enabled || !onFilterSortChange)
|
|
15
|
+
return null;
|
|
16
|
+
return (React.createElement(Fragment, null,
|
|
17
|
+
React.createElement(StyledIconButton, { color: ICON_BUTTON_PROPS.COLOR.INK_LIGHT, "data-testid": TEST_IDS.FILTER_SORT_BUTTON, onClick: onOpen, open: open },
|
|
18
|
+
React.createElement(SettingsOutlined, { ...SVG_ICON_PROPS })),
|
|
19
|
+
React.createElement(StyledMenu, { ...MENU_PROPS, anchorEl: anchorEl, "data-testid": TEST_IDS.FILTER_SORT_MENU, onClose: onClose, open: open },
|
|
20
|
+
React.createElement(ListItem, null,
|
|
21
|
+
React.createElement(ListItemText, { ...LIST_ITEM_TEXT_PROPS }, "Sort Filter Values By")),
|
|
22
|
+
React.createElement(ListItemButton, { onClick: () => onFilterSortChange(FILTER_SORT.ALPHA) },
|
|
23
|
+
React.createElement(Radio, { checked: filterSort === FILTER_SORT.ALPHA, checkedIcon: React.createElement(RadioCheckedIcon, { ...SVG_ICON_PROPS }), icon: React.createElement(RadioUncheckedIcon, { ...SVG_ICON_PROPS }) }),
|
|
24
|
+
React.createElement(ListItemText, { ...LIST_ITEM_BUTTON_TEXT_PROPS }, "Alphabetical")),
|
|
25
|
+
React.createElement(ListItemButton, { onClick: () => onFilterSortChange(FILTER_SORT.COUNT) },
|
|
26
|
+
React.createElement(Radio, { checked: filterSort === FILTER_SORT.COUNT, checkedIcon: React.createElement(RadioCheckedIcon, { ...SVG_ICON_PROPS }), icon: React.createElement(RadioUncheckedIcon, { ...SVG_ICON_PROPS }) }),
|
|
27
|
+
React.createElement(ListItemText, { ...LIST_ITEM_BUTTON_TEXT_PROPS }, "By Count (Descending)")))));
|
|
28
|
+
};
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { MenuProps } from "@mui/material";
|
|
2
|
+
export declare const StyledIconButton: import("@emotion/styled").StyledComponent<import("@mui/material").IconButtonOwnProps & Omit<import("@mui/material").ButtonBaseOwnProps, "classes"> & import("@mui/material/OverridableComponent").CommonProps & Omit<Omit<import("react").DetailedHTMLProps<import("react").ButtonHTMLAttributes<HTMLButtonElement>, HTMLButtonElement>, "ref"> & {
|
|
3
|
+
ref?: ((instance: HTMLButtonElement | null) => void | import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES[keyof import("react").DO_NOT_USE_OR_YOU_WILL_BE_FIRED_CALLBACK_REF_RETURN_VALUES]) | import("react").RefObject<HTMLButtonElement> | null | undefined;
|
|
4
|
+
}, "style" | "size" | "className" | "classes" | "action" | "centerRipple" | "children" | "disabled" | "disableRipple" | "disableTouchRipple" | "focusRipple" | "focusVisibleClassName" | "LinkComponent" | "onFocusVisible" | "sx" | "tabIndex" | "TouchRippleProps" | "touchRippleRef" | "color" | "disableFocusRipple" | "edge" | "loading" | "loadingIndicator"> & {
|
|
5
|
+
theme?: import("@emotion/react").Theme;
|
|
6
|
+
} & Pick<MenuProps, "open">, {}, {}>;
|
|
7
|
+
export declare const StyledMenu: import("@emotion/styled").StyledComponent<MenuProps & {
|
|
8
|
+
theme?: import("@emotion/react").Theme;
|
|
9
|
+
}, {}, {}>;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { css } from "@emotion/react";
|
|
2
|
+
import styled from "@emotion/styled";
|
|
3
|
+
import { IconButton, Menu, menuClasses, paperClasses, } from "@mui/material";
|
|
4
|
+
import { PALETTE } from "../../../../../../../styles/common/constants/palette";
|
|
5
|
+
import { MuiListItemButtonRoot } from "../../../../FilterList/filterList.styles";
|
|
6
|
+
export const StyledIconButton = styled(IconButton) `
|
|
7
|
+
align-self: center;
|
|
8
|
+
padding: 0;
|
|
9
|
+
|
|
10
|
+
${({ open }) => open &&
|
|
11
|
+
css `
|
|
12
|
+
color: ${PALETTE.INK_MAIN};
|
|
13
|
+
`}
|
|
14
|
+
`;
|
|
15
|
+
export const StyledMenu = styled(Menu) `
|
|
16
|
+
.${paperClasses.root} {
|
|
17
|
+
margin: 4px 0;
|
|
18
|
+
max-width: 300px;
|
|
19
|
+
width: 100%;
|
|
20
|
+
|
|
21
|
+
.${menuClasses.list} {
|
|
22
|
+
${MuiListItemButtonRoot}
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
`;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { FILTER_SORT } from "../../../../../../../../common/filters/sort/config/types";
|
|
2
|
+
import { FilterSort } from "../filterSort";
|
|
3
|
+
const meta = {
|
|
4
|
+
component: FilterSort,
|
|
5
|
+
};
|
|
6
|
+
export default meta;
|
|
7
|
+
export const DEFAULT = {
|
|
8
|
+
args: { enabled: true, filterSort: FILTER_SORT.ALPHA },
|
|
9
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,6 +1,5 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { SurfaceProps } from "../../surfaces/types";
|
|
1
|
+
import { ControlsProps } from "./types";
|
|
3
2
|
/**
|
|
4
3
|
* Renders filter title and "Clear All" button.
|
|
5
4
|
*/
|
|
6
|
-
export declare const Controls: ({ className, onFilter, }:
|
|
5
|
+
export declare const Controls: ({ className, filterSort, filterSortEnabled, onFilter, onFilterSortChange, }: ControlsProps) => JSX.Element | null;
|
|
@@ -3,12 +3,14 @@ import React from "react";
|
|
|
3
3
|
import { CLEAR_ALL } from "../../../../../common/entities";
|
|
4
4
|
import { TYPOGRAPHY_PROPS } from "../../../../../styles/common/mui/typography";
|
|
5
5
|
import { BUTTON_PROPS } from "../../../../common/Button/constants";
|
|
6
|
+
import { FilterSort } from "./components/FilterSort/filterSort";
|
|
6
7
|
import { StyledGrid } from "./controls.styles";
|
|
7
8
|
/**
|
|
8
9
|
* Renders filter title and "Clear All" button.
|
|
9
10
|
*/
|
|
10
|
-
export const Controls = ({ className, onFilter, }) => {
|
|
11
|
+
export const Controls = ({ className, filterSort, filterSortEnabled = false, onFilter, onFilterSortChange, }) => {
|
|
11
12
|
return (React.createElement(StyledGrid, { className: className, container: true },
|
|
12
13
|
React.createElement(Typography, { variant: TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_500 }, "Filters"),
|
|
13
|
-
React.createElement(MButton, { ...BUTTON_PROPS.PRIMARY_TEXT, onClick: () => onFilter(CLEAR_ALL, undefined, false) }, "Clear All")
|
|
14
|
+
React.createElement(MButton, { ...BUTTON_PROPS.PRIMARY_TEXT, onClick: () => onFilter(CLEAR_ALL, undefined, false) }, "Clear All"),
|
|
15
|
+
React.createElement(FilterSort, { enabled: filterSortEnabled, filterSort: filterSort, onFilterSortChange: onFilterSortChange })));
|
|
14
16
|
};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { BaseComponentProps } from "../../../../types";
|
|
2
|
+
import { SurfaceProps } from "../../surfaces/types";
|
|
3
|
+
import { FilterSortProps } from "./components/FilterSort/types";
|
|
4
|
+
export interface ControlsProps extends BaseComponentProps, Pick<SurfaceProps, "onFilter">, Omit<FilterSortProps, "enabled"> {
|
|
5
|
+
filterSortEnabled?: boolean;
|
|
6
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
|
|
2
2
|
import { CategoryFilter } from "../Filters/filters";
|
|
3
|
-
|
|
3
|
+
import { FilterSortProps } from "../controls/Controls/components/FilterSort/types";
|
|
4
|
+
export interface SurfaceProps extends Omit<FilterSortProps, "enabled"> {
|
|
4
5
|
categoryFilters: CategoryFilter[];
|
|
5
6
|
count?: number;
|
|
7
|
+
filterSortEnabled: boolean;
|
|
6
8
|
onFilter: OnFilterFn;
|
|
7
9
|
}
|
|
8
10
|
export declare enum SURFACE_TYPE {
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
+
import { sortCategoryValueViewsCount } from "../../../../../../../../../../../common/filters/sort/models/utils";
|
|
2
3
|
import { getPlotOptions } from "../../barX/plot";
|
|
3
4
|
import { getCategoryTotalCount } from "../../barX/utils";
|
|
4
|
-
import { sortByCountThenLabel } from "../../utils";
|
|
5
5
|
export const usePlotOptions = (selectCategoryValueViews, width, barCount) => {
|
|
6
6
|
// Organise the select category value views (sort and slice) for chart display.
|
|
7
7
|
const data = selectCategoryValueViews
|
|
8
8
|
// Sort the category values by count and label.
|
|
9
|
-
.sort(
|
|
9
|
+
.sort(sortCategoryValueViewsCount)
|
|
10
10
|
// Slice the category values to the number of bars to display.
|
|
11
11
|
.slice(0, barCount);
|
|
12
12
|
// Build the plot options.
|
|
@@ -6,10 +6,3 @@ import { SelectCategoryValueView } from "../../../../../../../../../common/entit
|
|
|
6
6
|
* @returns Button text.
|
|
7
7
|
*/
|
|
8
8
|
export declare function renderButtonText(maxBarCount: number | undefined, selectCategoryValueViews: SelectCategoryValueView[]): string;
|
|
9
|
-
/**
|
|
10
|
-
* Sorts category value views by count in descending order, then label in ascending order.
|
|
11
|
-
* @param a - First category value view.
|
|
12
|
-
* @param b - Second category value view.
|
|
13
|
-
* @returns Sorted category value views.
|
|
14
|
-
*/
|
|
15
|
-
export declare function sortByCountThenLabel(a: SelectCategoryValueView, b: SelectCategoryValueView): number;
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { sortCategoryValueViews } from "../../../../../../../../../hooks/useCategoryFilter";
|
|
2
1
|
/**
|
|
3
2
|
* Renders the button text for the chart.
|
|
4
3
|
* @param maxBarCount - Maximum number of bars to display.
|
|
@@ -13,13 +12,3 @@ export function renderButtonText(maxBarCount, selectCategoryValueViews) {
|
|
|
13
12
|
const count = totalBars - maxBarCount;
|
|
14
13
|
return `Show ${count} additional results`;
|
|
15
14
|
}
|
|
16
|
-
/**
|
|
17
|
-
* Sorts category value views by count in descending order, then label in ascending order.
|
|
18
|
-
* @param a - First category value view.
|
|
19
|
-
* @param b - Second category value view.
|
|
20
|
-
* @returns Sorted category value views.
|
|
21
|
-
*/
|
|
22
|
-
export function sortByCountThenLabel(a, b) {
|
|
23
|
-
const compare = b.count - a.count;
|
|
24
|
-
return compare === 0 ? sortCategoryValueViews(a, b) : compare;
|
|
25
|
-
}
|