@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.
Files changed (96) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +14 -0
  3. package/lib/common/filters/sort/config/types.d.ts +13 -0
  4. package/lib/common/filters/sort/config/types.js +8 -0
  5. package/lib/common/filters/sort/config/utils.d.ts +8 -0
  6. package/lib/common/filters/sort/config/utils.js +9 -0
  7. package/lib/common/filters/sort/models/utils.d.ts +23 -0
  8. package/lib/common/filters/sort/models/utils.js +41 -0
  9. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.js +6 -1
  10. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.d.ts +3 -0
  11. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.js +8 -0
  12. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.d.ts +6 -0
  13. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.js +1 -0
  14. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.d.ts +14 -0
  15. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.js +23 -0
  16. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.d.ts +2 -0
  17. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.d.ts +3 -1
  18. package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.js +24 -16
  19. package/lib/components/Filter/components/controls/Controls/components/FilterSort/constants.d.ts +5 -0
  20. package/lib/components/Filter/components/controls/Controls/components/FilterSort/constants.js +17 -0
  21. package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.d.ts +2 -0
  22. package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.js +28 -0
  23. package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.d.ts +9 -0
  24. package/lib/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.js +25 -0
  25. package/lib/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.d.ts +6 -0
  26. package/lib/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.js +9 -0
  27. package/lib/components/Filter/components/controls/Controls/components/FilterSort/types.d.ts +6 -0
  28. package/lib/components/Filter/components/controls/Controls/components/FilterSort/types.js +1 -0
  29. package/lib/components/Filter/components/controls/Controls/controls.d.ts +2 -3
  30. package/lib/components/Filter/components/controls/Controls/controls.js +4 -2
  31. package/lib/components/Filter/components/controls/Controls/controls.styles.js +2 -1
  32. package/lib/components/Filter/components/controls/Controls/types.d.ts +6 -0
  33. package/lib/components/Filter/components/controls/Controls/types.js +1 -0
  34. package/lib/components/Filter/components/surfaces/types.d.ts +3 -1
  35. package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.js +2 -2
  36. package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.d.ts +0 -7
  37. package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.js +0 -11
  38. package/lib/config/entities.d.ts +2 -0
  39. package/lib/hooks/useCategoryFilter.d.ts +4 -9
  40. package/lib/hooks/useCategoryFilter.js +5 -15
  41. package/lib/providers/exploreState/actions/updateFilterSort/action.d.ts +10 -0
  42. package/lib/providers/exploreState/actions/updateFilterSort/action.js +21 -0
  43. package/lib/providers/exploreState/actions/updateFilterSort/dispatch.d.ts +7 -0
  44. package/lib/providers/exploreState/actions/updateFilterSort/dispatch.js +12 -0
  45. package/lib/providers/exploreState/actions/updateFilterSort/types.d.ts +7 -0
  46. package/lib/providers/exploreState/actions/updateFilterSort/types.js +1 -0
  47. package/lib/providers/exploreState/actions/updateFilterSort/utils.d.ts +10 -0
  48. package/lib/providers/exploreState/actions/updateFilterSort/utils.js +22 -0
  49. package/lib/providers/exploreState/initializer/constants.js +2 -0
  50. package/lib/providers/exploreState/initializer/utils.js +2 -0
  51. package/lib/providers/exploreState.d.ts +5 -1
  52. package/lib/providers/exploreState.js +9 -1
  53. package/lib/tests/testIds.d.ts +2 -0
  54. package/lib/tests/testIds.js +2 -0
  55. package/lib/views/ExploreView/exploreView.js +7 -1
  56. package/lib/views/ExploreView/hooks/UseUpdateFilterSort/hook.d.ts +2 -0
  57. package/lib/views/ExploreView/hooks/UseUpdateFilterSort/hook.js +12 -0
  58. package/lib/views/ExploreView/hooks/UseUpdateFilterSort/types.d.ts +6 -0
  59. package/lib/views/ExploreView/hooks/UseUpdateFilterSort/types.js +1 -0
  60. package/package.json +1 -1
  61. package/src/common/filters/sort/config/types.ts +14 -0
  62. package/src/common/filters/sort/config/utils.ts +11 -0
  63. package/src/common/filters/sort/models/utils.ts +57 -0
  64. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/columnFiltersAdapter.tsx +11 -1
  65. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/hook.ts +22 -0
  66. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/types.ts +7 -0
  67. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/hooks/UseUpdateFilterSort/utils.ts +33 -0
  68. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/types.ts +2 -0
  69. package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.ts +36 -13
  70. package/src/components/Filter/components/controls/Controls/components/FilterSort/constants.ts +22 -0
  71. package/src/components/Filter/components/controls/Controls/components/FilterSort/filterSort.styles.ts +34 -0
  72. package/src/components/Filter/components/controls/Controls/components/FilterSort/filterSort.tsx +73 -0
  73. package/src/components/Filter/components/controls/Controls/components/FilterSort/stories/filterSort.stories.tsx +15 -0
  74. package/src/components/Filter/components/controls/Controls/components/FilterSort/types.ts +7 -0
  75. package/src/components/Filter/components/controls/Controls/controls.styles.ts +2 -1
  76. package/src/components/Filter/components/controls/Controls/controls.tsx +11 -3
  77. package/src/components/Filter/components/controls/Controls/types.ts +10 -0
  78. package/src/components/Filter/components/surfaces/types.ts +3 -1
  79. package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.ts +2 -2
  80. package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/utils.ts +0 -15
  81. package/src/config/entities.ts +2 -0
  82. package/src/hooks/useCategoryFilter.ts +8 -19
  83. package/src/providers/exploreState/actions/updateFilterSort/action.ts +30 -0
  84. package/src/providers/exploreState/actions/updateFilterSort/dispatch.ts +16 -0
  85. package/src/providers/exploreState/actions/updateFilterSort/types.ts +9 -0
  86. package/src/providers/exploreState/actions/updateFilterSort/utils.ts +30 -0
  87. package/src/providers/exploreState/initializer/constants.ts +2 -0
  88. package/src/providers/exploreState/initializer/utils.ts +2 -0
  89. package/src/providers/exploreState.tsx +14 -1
  90. package/src/tests/testIds.ts +2 -0
  91. package/src/views/ExploreView/exploreView.tsx +16 -1
  92. package/src/views/ExploreView/hooks/UseUpdateFilterSort/hook.ts +20 -0
  93. package/src/views/ExploreView/hooks/UseUpdateFilterSort/types.ts +7 -0
  94. package/tests/buildCategoryViews.test.ts +282 -0
  95. package/tests/filterSortUtils.test.ts +180 -0
  96. package/tests/getFilterSortType.test.ts +45 -0
@@ -7,9 +7,10 @@ import {
7
7
  SelectCategoryValueView,
8
8
  SelectCategoryView,
9
9
  } from "../../../../../../common/entities";
10
+ import { FILTER_SORT } from "../../../../../../common/filters/sort/config/types";
11
+ import { sortCategoryValueViews } from "../../../../../../common/filters/sort/models/utils";
10
12
  import { CategoryGroup } from "../../../../../../config/entities";
11
13
  import { getColumnHeader } from "../../../../../Table/common/utils";
12
- import { getSortedFacetedValues } from "../../../../../Table/featureOptions/facetedColumn/utils";
13
14
  import { CategoryFilter } from "../../../Filters/filters";
14
15
  import { SurfaceProps } from "../../../surfaces/types";
15
16
  import { ColumnFiltersTableMeta } from "./types";
@@ -31,16 +32,22 @@ function buildCategoryConfigs<T extends RowData>(
31
32
  /**
32
33
  * Adapter for TanStack table to category filters.
33
34
  * @param table - Table.
35
+ * @param filterSort - Filter sort.
34
36
  * @param categoryGroups - Category groups.
35
37
  * @returns Category filters.
36
38
  */
37
39
  function buildCategoryFilters<T extends RowData>(
38
40
  table: Table<T>,
41
+ filterSort: FILTER_SORT,
39
42
  categoryGroups: CategoryGroup[]
40
43
  ): SurfaceProps["categoryFilters"] {
41
44
  return categoryGroups.reduce<SurfaceProps["categoryFilters"]>(
42
45
  (acc, categoryGroup) => {
43
- const categoryFilter = mapCategoryFilter(table, categoryGroup);
46
+ const categoryFilter = mapCategoryFilter(
47
+ table,
48
+ filterSort,
49
+ categoryGroup
50
+ );
44
51
  if (categoryFilter) acc.push(categoryFilter);
45
52
  return acc;
46
53
  },
@@ -51,10 +58,12 @@ function buildCategoryFilters<T extends RowData>(
51
58
  /**
52
59
  * Adapter for TanStack table column filters to category filters.
53
60
  * @param table - Table.
61
+ * @param filterSort - Filter sort.
54
62
  * @returns Category filters.
55
63
  */
56
64
  export function buildColumnFilters<T extends RowData>(
57
- table: Table<T>
65
+ table: Table<T>,
66
+ filterSort = FILTER_SORT.ALPHA
58
67
  ): SurfaceProps["categoryFilters"] {
59
68
  const { options } = table;
60
69
  const { meta = {} } = options;
@@ -64,11 +73,13 @@ export function buildColumnFilters<T extends RowData>(
64
73
  // Build single category group with all (filterable) columns.
65
74
  const categoryConfigs: CategoryConfig[] = buildCategoryConfigs(table);
66
75
  // Build category filters from single category group.
67
- return buildCategoryFilters(table, [{ categoryConfigs, label: "" }]);
76
+ return buildCategoryFilters(table, filterSort, [
77
+ { categoryConfigs, label: "" },
78
+ ]);
68
79
  }
69
80
 
70
81
  // Build category filters from category groups.
71
- return buildCategoryFilters(table, categoryGroups);
82
+ return buildCategoryFilters(table, filterSort, categoryGroups);
72
83
  }
73
84
 
74
85
  /**
@@ -104,11 +115,13 @@ function mapCategoryConfig<T extends RowData>(
104
115
  /**
105
116
  * Adapter for TanStack table to category filter.
106
117
  * @param table - Table.
118
+ * @param filterSort - Filter sort.
107
119
  * @param categoryGroup - Category group.
108
120
  * @returns Category filter.
109
121
  */
110
122
  function mapCategoryFilter<T extends RowData>(
111
123
  table: Table<T>,
124
+ filterSort: FILTER_SORT,
112
125
  categoryGroup: CategoryGroup
113
126
  ): CategoryFilter | undefined {
114
127
  const { categoryConfigs, label } = categoryGroup;
@@ -126,7 +139,11 @@ function mapCategoryFilter<T extends RowData>(
126
139
  categoryView = mapColumnToRangeCategoryView(column, categoryConfig);
127
140
  } else {
128
141
  // Build select category view.
129
- categoryView = mapColumnToSelectCategoryView(column, categoryConfig);
142
+ categoryView = mapColumnToSelectCategoryView(
143
+ column,
144
+ filterSort,
145
+ categoryConfig
146
+ );
130
147
  }
131
148
 
132
149
  return [...acc, categoryView];
@@ -174,16 +191,18 @@ function mapColumnToRangeCategoryView<T extends RowData>(
174
191
  /**
175
192
  * Adapter for TanStack column to select category view.
176
193
  * @param column - Column.
194
+ * @param filterSort - Filter sort.
177
195
  * @param categoryConfig - Category config.
178
196
  * @returns Select category view.
179
197
  */
180
198
  function mapColumnToSelectCategoryView<T extends RowData>(
181
199
  column: Column<T>,
200
+ filterSort: FILTER_SORT,
182
201
  categoryConfig?: CategoryConfig
183
202
  ): SelectCategoryView {
184
203
  const facetedUniqueValues = column.getFacetedUniqueValues();
185
204
  const isDisabled = facetedUniqueValues.size === 0;
186
- const values = mapColumnToSelectCategoryValueView(column);
205
+ const values = mapColumnToSelectCategoryValueView(column, filterSort);
187
206
  return {
188
207
  annotation: undefined,
189
208
  enableChartView: false,
@@ -198,22 +217,24 @@ function mapColumnToSelectCategoryView<T extends RowData>(
198
217
  /**
199
218
  * Adapter for TanStack column to select category value view.
200
219
  * @param column - Column.
220
+ * @param filterSort - Filter sort.
201
221
  * @returns Select category value view.
202
222
  */
203
223
  function mapColumnToSelectCategoryValueView<T extends RowData>(
204
- column: Column<T>
224
+ column: Column<T>,
225
+ filterSort: FILTER_SORT
205
226
  ): SelectCategoryValueView[] {
206
227
  // Get the faceted unique values and sort them.
207
228
  const facetedUniqueValues = column.getFacetedUniqueValues();
208
- const sortedFacetsValues = getSortedFacetedValues(facetedUniqueValues);
209
229
 
210
230
  // Selected values for the column.
211
231
  const filterValue = (column.getFilterValue() || []) as unknown[];
212
232
 
213
233
  // Build the select category values.
214
- const selectCategoryValues: SelectCategoryValueView[] = [];
215
- for (const [label, count] of sortedFacetsValues) {
216
- selectCategoryValues.push({
234
+ const categoryValueViews: SelectCategoryValueView[] = [];
235
+
236
+ for (const [label, count] of [...facetedUniqueValues]) {
237
+ categoryValueViews.push({
217
238
  count,
218
239
  key: String(label),
219
240
  label: String(label),
@@ -221,5 +242,7 @@ function mapColumnToSelectCategoryValueView<T extends RowData>(
221
242
  });
222
243
  }
223
244
 
224
- return selectCategoryValues;
245
+ sortCategoryValueViews(categoryValueViews, filterSort);
246
+
247
+ return categoryValueViews;
225
248
  }
@@ -0,0 +1,22 @@
1
+ import { ListItemTextProps, MenuProps, SvgIconProps } from "@mui/material";
2
+ import { SVG_ICON_PROPS as MUI_SVG_ICON_PROPS } from "../../../../../../../styles/common/mui/svgIcon";
3
+ import { TYPOGRAPHY_PROPS } from "../../../../../../../styles/common/mui/typography";
4
+
5
+ export const LIST_ITEM_BUTTON_TEXT_PROPS: ListItemTextProps = {
6
+ slotProps: { primary: { variant: TYPOGRAPHY_PROPS.VARIANT.BODY_400 } },
7
+ };
8
+
9
+ export const LIST_ITEM_TEXT_PROPS: ListItemTextProps = {
10
+ slotProps: { primary: { variant: TYPOGRAPHY_PROPS.VARIANT.BODY_500 } },
11
+ };
12
+
13
+ export const MENU_PROPS: Omit<MenuProps, "anchorEl" | "onClose" | "open"> = {
14
+ anchorOrigin: { horizontal: "left", vertical: "bottom" },
15
+ marginThreshold: 8,
16
+ slotProps: { paper: { variant: "menu" } },
17
+ transformOrigin: { horizontal: "left", vertical: "top" },
18
+ };
19
+
20
+ export const SVG_ICON_PROPS: SvgIconProps = {
21
+ fontSize: MUI_SVG_ICON_PROPS.FONT_SIZE.SMALL,
22
+ };
@@ -0,0 +1,34 @@
1
+ import { css } from "@emotion/react";
2
+ import styled from "@emotion/styled";
3
+ import {
4
+ IconButton,
5
+ Menu,
6
+ MenuProps,
7
+ menuClasses,
8
+ paperClasses,
9
+ } from "@mui/material";
10
+ import { PALETTE } from "../../../../../../../styles/common/constants/palette";
11
+ import { MuiListItemButtonRoot } from "../../../../FilterList/filterList.styles";
12
+
13
+ export const StyledIconButton = styled(IconButton)<Pick<MenuProps, "open">>`
14
+ align-self: center;
15
+ padding: 0;
16
+
17
+ ${({ open }) =>
18
+ open &&
19
+ css`
20
+ color: ${PALETTE.INK_MAIN};
21
+ `}
22
+ `;
23
+
24
+ export const StyledMenu = styled(Menu)`
25
+ .${paperClasses.root} {
26
+ margin: 4px 0;
27
+ max-width: 300px;
28
+ width: 100%;
29
+
30
+ .${menuClasses.list} {
31
+ ${MuiListItemButtonRoot}
32
+ }
33
+ }
34
+ `;
@@ -0,0 +1,73 @@
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 {
11
+ LIST_ITEM_BUTTON_TEXT_PROPS,
12
+ LIST_ITEM_TEXT_PROPS,
13
+ MENU_PROPS,
14
+ SVG_ICON_PROPS,
15
+ } from "./constants";
16
+ import { StyledIconButton, StyledMenu } from "./filterSort.styles";
17
+ import { FilterSortProps } from "./types";
18
+
19
+ export const FilterSort = ({
20
+ enabled = false,
21
+ filterSort = FILTER_SORT.ALPHA,
22
+ onFilterSortChange,
23
+ }: FilterSortProps): JSX.Element | null => {
24
+ const { anchorEl, onClose, onOpen, open } = useMenu();
25
+
26
+ if (!enabled || !onFilterSortChange) return null;
27
+
28
+ return (
29
+ <Fragment>
30
+ <StyledIconButton
31
+ color={ICON_BUTTON_PROPS.COLOR.INK_LIGHT}
32
+ data-testid={TEST_IDS.FILTER_SORT_BUTTON}
33
+ onClick={onOpen}
34
+ open={open}
35
+ >
36
+ <SettingsOutlined {...SVG_ICON_PROPS} />
37
+ </StyledIconButton>
38
+ <StyledMenu
39
+ {...MENU_PROPS}
40
+ anchorEl={anchorEl}
41
+ data-testid={TEST_IDS.FILTER_SORT_MENU}
42
+ onClose={onClose}
43
+ open={open}
44
+ >
45
+ <ListItem>
46
+ <ListItemText {...LIST_ITEM_TEXT_PROPS}>
47
+ Sort Filter Values By
48
+ </ListItemText>
49
+ </ListItem>
50
+ <ListItemButton onClick={() => onFilterSortChange(FILTER_SORT.ALPHA)}>
51
+ <Radio
52
+ checked={filterSort === FILTER_SORT.ALPHA}
53
+ checkedIcon={<RadioCheckedIcon {...SVG_ICON_PROPS} />}
54
+ icon={<RadioUncheckedIcon {...SVG_ICON_PROPS} />}
55
+ />
56
+ <ListItemText {...LIST_ITEM_BUTTON_TEXT_PROPS}>
57
+ Alphabetical
58
+ </ListItemText>
59
+ </ListItemButton>
60
+ <ListItemButton onClick={() => onFilterSortChange(FILTER_SORT.COUNT)}>
61
+ <Radio
62
+ checked={filterSort === FILTER_SORT.COUNT}
63
+ checkedIcon={<RadioCheckedIcon {...SVG_ICON_PROPS} />}
64
+ icon={<RadioUncheckedIcon {...SVG_ICON_PROPS} />}
65
+ />
66
+ <ListItemText {...LIST_ITEM_BUTTON_TEXT_PROPS}>
67
+ By Count (Descending)
68
+ </ListItemText>
69
+ </ListItemButton>
70
+ </StyledMenu>
71
+ </Fragment>
72
+ );
73
+ };
@@ -0,0 +1,15 @@
1
+ import { Meta, StoryObj } from "@storybook/react";
2
+ import { FILTER_SORT } from "../../../../../../../../common/filters/sort/config/types";
3
+ import { FilterSort } from "../filterSort";
4
+
5
+ const meta: Meta<typeof FilterSort> = {
6
+ component: FilterSort,
7
+ };
8
+
9
+ export default meta;
10
+
11
+ type Story = StoryObj<typeof meta>;
12
+
13
+ export const DEFAULT: Story = {
14
+ args: { enabled: true, filterSort: FILTER_SORT.ALPHA },
15
+ };
@@ -0,0 +1,7 @@
1
+ import { FILTER_SORT } from "../../../../../../../common/filters/sort/config/types";
2
+
3
+ export type FilterSortProps = {
4
+ enabled?: boolean;
5
+ filterSort?: FILTER_SORT;
6
+ onFilterSortChange?: (filterSort: FILTER_SORT) => void;
7
+ };
@@ -3,7 +3,8 @@ import { Grid } from "@mui/material";
3
3
 
4
4
  export const StyledGrid = styled(Grid)`
5
5
  display: grid;
6
- gap: 8px 0;
6
+ gap: 8px 16px;
7
+ grid-auto-flow: column;
7
8
  grid-template-columns: 1fr auto;
8
9
  margin: 8px 0;
9
10
  padding: 0 16px;
@@ -3,9 +3,9 @@ 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 { BaseComponentProps } from "../../../../types";
7
- import { SurfaceProps } from "../../surfaces/types";
6
+ import { FilterSort } from "./components/FilterSort/filterSort";
8
7
  import { StyledGrid } from "./controls.styles";
8
+ import { ControlsProps } from "./types";
9
9
 
10
10
  /**
11
11
  * Renders filter title and "Clear All" button.
@@ -13,8 +13,11 @@ import { StyledGrid } from "./controls.styles";
13
13
 
14
14
  export const Controls = ({
15
15
  className,
16
+ filterSort,
17
+ filterSortEnabled = false,
16
18
  onFilter,
17
- }: BaseComponentProps & Pick<SurfaceProps, "onFilter">): JSX.Element | null => {
19
+ onFilterSortChange,
20
+ }: ControlsProps): JSX.Element | null => {
18
21
  return (
19
22
  <StyledGrid className={className} container>
20
23
  <Typography variant={TYPOGRAPHY_PROPS.VARIANT.BODY_LARGE_500}>
@@ -26,6 +29,11 @@ export const Controls = ({
26
29
  >
27
30
  Clear All
28
31
  </MButton>
32
+ <FilterSort
33
+ enabled={filterSortEnabled}
34
+ filterSort={filterSort}
35
+ onFilterSortChange={onFilterSortChange}
36
+ />
29
37
  </StyledGrid>
30
38
  );
31
39
  };
@@ -0,0 +1,10 @@
1
+ import { BaseComponentProps } from "../../../../types";
2
+ import { SurfaceProps } from "../../surfaces/types";
3
+ import { FilterSortProps } from "./components/FilterSort/types";
4
+
5
+ export interface ControlsProps
6
+ extends BaseComponentProps,
7
+ Pick<SurfaceProps, "onFilter">,
8
+ Omit<FilterSortProps, "enabled"> {
9
+ filterSortEnabled?: boolean;
10
+ }
@@ -1,9 +1,11 @@
1
1
  import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
2
2
  import { CategoryFilter } from "../Filters/filters";
3
+ import { FilterSortProps } from "../controls/Controls/components/FilterSort/types";
3
4
 
4
- export interface SurfaceProps {
5
+ export interface SurfaceProps extends Omit<FilterSortProps, "enabled"> {
5
6
  categoryFilters: CategoryFilter[];
6
7
  count?: number;
8
+ filterSortEnabled: boolean;
7
9
  onFilter: OnFilterFn;
8
10
  }
9
11
 
@@ -1,8 +1,8 @@
1
1
  import { useMemo } from "react";
2
2
  import { SelectCategoryValueView } from "../../../../../../../../../../../common/entities";
3
+ import { sortCategoryValueViewsCount } from "../../../../../../../../../../../common/filters/sort/models/utils";
3
4
  import { getPlotOptions } from "../../barX/plot";
4
5
  import { getCategoryTotalCount } from "../../barX/utils";
5
- import { sortByCountThenLabel } from "../../utils";
6
6
  import { UsePlotOptions } from "./types";
7
7
 
8
8
  export const usePlotOptions = (
@@ -13,7 +13,7 @@ export const usePlotOptions = (
13
13
  // Organise the select category value views (sort and slice) for chart display.
14
14
  const data = selectCategoryValueViews
15
15
  // Sort the category values by count and label.
16
- .sort(sortByCountThenLabel)
16
+ .sort(sortCategoryValueViewsCount)
17
17
  // Slice the category values to the number of bars to display.
18
18
  .slice(0, barCount);
19
19
 
@@ -1,5 +1,4 @@
1
1
  import { SelectCategoryValueView } from "../../../../../../../../../common/entities";
2
- import { sortCategoryValueViews } from "../../../../../../../../../hooks/useCategoryFilter";
3
2
 
4
3
  /**
5
4
  * Renders the button text for the chart.
@@ -19,17 +18,3 @@ export function renderButtonText(
19
18
 
20
19
  return `Show ${count} additional results`;
21
20
  }
22
-
23
- /**
24
- * Sorts category value views by count in descending order, then label in ascending order.
25
- * @param a - First category value view.
26
- * @param b - Second category value view.
27
- * @returns Sorted category value views.
28
- */
29
- export function sortByCountThenLabel(
30
- a: SelectCategoryValueView,
31
- b: SelectCategoryValueView
32
- ): number {
33
- const compare = b.count - a.count;
34
- return compare === 0 ? sortCategoryValueViews(a, b) : compare;
35
- }
@@ -17,6 +17,7 @@ import {
17
17
  DataDictionaryConfig,
18
18
  SelectedFilter,
19
19
  } from "../common/entities";
20
+ import { FilterSortConfig } from "../common/filters/sort/config/types";
20
21
  import { FooterProps } from "../components/Layout/components/Footer/footer";
21
22
  import { HeaderProps } from "../components/Layout/components/Header/header";
22
23
  import { ExploreMode } from "../hooks/useExploreMode/types";
@@ -378,6 +379,7 @@ export interface SiteConfig {
378
379
  export?: ExportConfig;
379
380
  exportsRequireAuth?: boolean;
380
381
  exportToTerraUrl?: string; // TODO(cc) revist location; possibly nest inside "export"?
382
+ filterSort?: FilterSortConfig;
381
383
  gitHubUrl?: string;
382
384
  layout: {
383
385
  floating?: FloatingConfig;
@@ -18,6 +18,8 @@ import {
18
18
  SelectCategoryView,
19
19
  SelectedFilter,
20
20
  } from "../common/entities";
21
+ import { FILTER_SORT } from "../common/filters/sort/config/types";
22
+ import { sortCategoryValueViews } from "../common/filters/sort/models/utils";
21
23
 
22
24
  /**
23
25
  * State backing filter functionality and calculations. Converted to view model for display.
@@ -94,12 +96,14 @@ function buildCategoryView(
94
96
  * @param categories - Categories, category value and their counts with the current filter applied.
95
97
  * @param categoryConfigs - Category configs indicating accept list as well as label configuration.
96
98
  * @param filterState - Current set of selected category and category values.
99
+ * @param filterSort - Sort configuration (ALPHA or COUNT).
97
100
  * @returns Array of category view objects.
98
101
  */
99
102
  export function buildCategoryViews(
100
103
  categories: Category[],
101
104
  categoryConfigs: CategoryConfig[] | undefined,
102
- filterState: FilterState
105
+ filterState: FilterState,
106
+ filterSort: FILTER_SORT
103
107
  ): CategoryView[] {
104
108
  if (!categories || !categoryConfigs) {
105
109
  return [];
@@ -131,7 +135,9 @@ export function buildCategoryViews(
131
135
  const categoryValueViews = category.values.map((categoryValue) =>
132
136
  buildCategoryValueView(categoryValue, categorySelectedFilter)
133
137
  );
134
- categoryValueViews.sort(sortCategoryValueViews);
138
+
139
+ // Sort category value views based on filter sort configuration.
140
+ sortCategoryValueViews(categoryValueViews, filterSort);
135
141
 
136
142
  // Build category view model.
137
143
  return buildCategoryView(category, categoryValueViews, categoryConfigs);
@@ -272,23 +278,6 @@ function isCategoryAcceptListed(
272
278
  );
273
279
  }
274
280
 
275
- /**
276
- * Sort category value views by key, ascending.
277
- * @param cvv0 - First category value view to compare.
278
- * @param cvv1 - Second category value view to compare.
279
- * @returns Number indicating sort precedence of cv0 vs cv1.
280
- */
281
- export function sortCategoryValueViews(
282
- cvv0: SelectCategoryValueView,
283
- cvv1: SelectCategoryValueView
284
- ): number {
285
- return !cvv0.label
286
- ? 1
287
- : !cvv1.label
288
- ? -1
289
- : COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
290
- }
291
-
292
281
  /**
293
282
  * Sort category views by display label, ascending.
294
283
  * @param c0 - First category view to compare.
@@ -0,0 +1,30 @@
1
+ import { ExploreState } from "../../../exploreState";
2
+ import { updateEntityStateByCategoryGroupConfigKey } from "../../utils";
3
+ import { UpdateFilterSortPayload } from "./types";
4
+ import { sortCategoryViews } from "./utils";
5
+
6
+ /**
7
+ * Reducer function to handle the "update filter sort" action.
8
+ * Updates the filter sort in the state for the current entity.
9
+ * @param state - Explore State.
10
+ * @param payload - Payload.
11
+ * @returns explore state.
12
+ */
13
+ export function updateFilterSortAction(
14
+ state: ExploreState,
15
+ payload: UpdateFilterSortPayload
16
+ ): ExploreState {
17
+ const filterSort = payload;
18
+
19
+ // Sort the category views based on the new filter sort.
20
+ const categoryViews = sortCategoryViews(state, filterSort);
21
+
22
+ // Update entity state by category group config key
23
+ updateEntityStateByCategoryGroupConfigKey(state, { categoryViews });
24
+
25
+ return {
26
+ ...state,
27
+ categoryViews,
28
+ filterSort,
29
+ };
30
+ }
@@ -0,0 +1,16 @@
1
+ import { ExploreActionKind } from "../../../exploreState";
2
+ import { UpdateFilterSortAction, UpdateFilterSortPayload } from "./types";
3
+
4
+ /**
5
+ * Action creator for updating filter sort in the state.
6
+ * @param payload - Payload.
7
+ * @returns Action with payload and action type.
8
+ */
9
+ export function updateFilterSort(
10
+ payload: UpdateFilterSortPayload
11
+ ): UpdateFilterSortAction {
12
+ return {
13
+ payload,
14
+ type: ExploreActionKind.UpdateFilterSort,
15
+ };
16
+ }
@@ -0,0 +1,9 @@
1
+ import { FILTER_SORT } from "../../../../common/filters/sort/config/types";
2
+ import { ExploreActionKind } from "../../../exploreState";
3
+
4
+ export type UpdateFilterSortAction = {
5
+ payload: UpdateFilterSortPayload;
6
+ type: ExploreActionKind.UpdateFilterSort;
7
+ };
8
+
9
+ export type UpdateFilterSortPayload = FILTER_SORT;
@@ -0,0 +1,30 @@
1
+ import { isRangeCategory } from "../../../../common/categories/models/range/typeGuards";
2
+ import { CategoryView } from "../../../../common/categories/views/types";
3
+ import { FILTER_SORT } from "../../../../common/filters/sort/config/types";
4
+ import { sortCategoryValueViews } from "../../../../common/filters/sort/models/utils";
5
+ import { ExploreState } from "../../../exploreState";
6
+
7
+ /**
8
+ * Sorts the category views for the current entity type, based on the filter sort.
9
+ * @param state - Explore state.
10
+ * @param filterSort - Filter sort.
11
+ * @returns Sorted category views.
12
+ */
13
+ export function sortCategoryViews(
14
+ state: ExploreState,
15
+ filterSort: FILTER_SORT
16
+ ): CategoryView[] {
17
+ return [...state.categoryViews].map((categoryView) => {
18
+ // Skip range categories.
19
+ if (isRangeCategory(categoryView)) return categoryView;
20
+
21
+ // Use structural clone for select categories that need sorting.
22
+ const nextCategoryView = {
23
+ ...categoryView,
24
+ values: [...categoryView.values],
25
+ };
26
+
27
+ sortCategoryValueViews(nextCategoryView.values, filterSort);
28
+ return nextCategoryView;
29
+ });
30
+ }
@@ -1,3 +1,4 @@
1
+ import { FILTER_SORT } from "../../../common/filters/sort/config/types";
1
2
  import { CategoryGroup } from "../../../config/entities";
2
3
  import { ExploreState, PaginationState } from "../../exploreState";
3
4
  import { SELECT_CATEGORY_KEY } from "../constants";
@@ -34,6 +35,7 @@ export const INITIAL_STATE: ExploreState = {
34
35
  entityStateByCategoryGroupConfigKey: new Map(),
35
36
  featureFlagState: undefined,
36
37
  filterCount: 0,
38
+ filterSort: FILTER_SORT.ALPHA,
37
39
  filterState: [],
38
40
  listItems: [],
39
41
  loading: true,
@@ -5,6 +5,7 @@ import {
5
5
  } from "@tanstack/react-table";
6
6
  import { CategoryConfig } from "../../../common/categories/config/types";
7
7
  import { SelectCategory, SelectedFilter } from "../../../common/entities";
8
+ import { getFilterSortType } from "../../../common/filters/sort/config/utils";
8
9
  import { getInitialColumnVisibilityState } from "../../../components/TableCreator/options/initialState/columnVisibility";
9
10
  import {
10
11
  CategoryGroup,
@@ -325,6 +326,7 @@ export function initReducerArguments(
325
326
  entityStateByCategoryGroupConfigKey,
326
327
  featureFlagState: decodedFeatureFlagParam,
327
328
  filterCount: getFilterCount(filterState),
329
+ filterSort: getFilterSortType(config),
328
330
  filterState,
329
331
  tabValue: entityListType,
330
332
  };