@databiosphere/findable-ui 17.0.0 → 18.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 (30) hide show
  1. package/.release-please-manifest.json +1 -1
  2. package/CHANGELOG.md +11 -0
  3. package/lib/apis/azul/common/filterTransformer.js +1 -1
  4. package/lib/apis/azul/common/utils.d.ts +1 -1
  5. package/lib/apis/azul/common/utils.js +5 -1
  6. package/lib/common/entities.d.ts +3 -3
  7. package/lib/components/Filter/common/utils.js +1 -1
  8. package/lib/components/Filter/components/VariableSizeList/VariableSizeList.d.ts +1 -1
  9. package/lib/components/Filter/components/VariableSizeListItem/variableSizeListItem.d.ts +1 -1
  10. package/lib/components/Table/common/utils.js +1 -1
  11. package/lib/config/entities.d.ts +1 -1
  12. package/lib/hooks/useCategoryFilter.js +5 -1
  13. package/lib/providers/fileManifestState.js +2 -4
  14. package/lib/viewModelBuilders/common/utils.d.ts +6 -6
  15. package/lib/viewModelBuilders/common/utils.js +10 -10
  16. package/lib/views/ExploreView/exploreView.js +1 -1
  17. package/package.json +1 -1
  18. package/src/apis/azul/common/filterTransformer.ts +1 -1
  19. package/src/apis/azul/common/utils.ts +4 -2
  20. package/src/common/entities.ts +3 -3
  21. package/src/components/Filter/common/utils.ts +1 -1
  22. package/src/components/Filter/components/VariableSizeList/VariableSizeList.tsx +1 -1
  23. package/src/components/Filter/components/VariableSizeListItem/variableSizeListItem.tsx +1 -1
  24. package/src/components/Table/common/utils.ts +1 -1
  25. package/src/config/entities.ts +1 -1
  26. package/src/hooks/useCategoryFilter.ts +5 -1
  27. package/src/hooks/useFileManifest/common/utils.ts +2 -2
  28. package/src/providers/fileManifestState.tsx +2 -4
  29. package/src/viewModelBuilders/common/utils.ts +10 -10
  30. package/src/views/ExploreView/exploreView.tsx +1 -1
@@ -1,3 +1,3 @@
1
1
  {
2
- ".": "17.0.0"
2
+ ".": "18.0.0"
3
3
  }
package/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
 
3
+ ## [18.0.0](https://github.com/DataBiosphere/findable-ui/compare/v17.0.0...v18.0.0) (2024-12-18)
4
+
5
+
6
+ ### ⚠ BREAKING CHANGES
7
+
8
+ * ensure select category value label is string and type key as unknown ([#298](https://github.com/DataBiosphere/findable-ui/issues/298)) (#299)
9
+
10
+ ### Bug Fixes
11
+
12
+ * ensure select category value label is string and type key as unknown ([#298](https://github.com/DataBiosphere/findable-ui/issues/298)) ([#299](https://github.com/DataBiosphere/findable-ui/issues/299)) ([c7b5baa](https://github.com/DataBiosphere/findable-ui/commit/c7b5baae525f6e54493a2748070fa46cc36d9f67))
13
+
3
14
  ## [17.0.0](https://github.com/DataBiosphere/findable-ui/compare/v16.1.0...v17.0.0) (2024-12-12)
4
15
 
5
16
 
@@ -88,7 +88,7 @@ export function transformTermFacets(termFacets, filterState) {
88
88
  categoryValues.push({
89
89
  count: 0,
90
90
  key: term,
91
- label: term ?? LABEL.UNSPECIFIED,
91
+ label: String(term ?? LABEL.UNSPECIFIED),
92
92
  selected: false, // Selected state updated in filter hook
93
93
  });
94
94
  }
@@ -4,4 +4,4 @@ import { ParamValue } from "./filterTransformer";
4
4
  * @param value - Filter value.
5
5
  * @returns filter parameter value.
6
6
  */
7
- export declare function getFilterParameterValue(value: string): ParamValue;
7
+ export declare function getFilterParameterValue(value: unknown): ParamValue;
@@ -13,5 +13,9 @@ export function getFilterParameterValue(value) {
13
13
  if (value === "false") {
14
14
  return false;
15
15
  }
16
- return value;
16
+ if (typeof value === "string" || typeof value === "boolean")
17
+ return value;
18
+ if (value === null || value === undefined)
19
+ return null;
20
+ return String(value);
17
21
  }
@@ -13,7 +13,7 @@ export interface CategoryTag {
13
13
  /**
14
14
  * Category values to be used as keys. For example, "Homo sapiens" or "10X 3' v2 sequencing".
15
15
  */
16
- export type CategoryValueKey = string;
16
+ export type CategoryValueKey = unknown;
17
17
  /**
18
18
  * Set of selected category values.
19
19
  */
@@ -46,7 +46,7 @@ export interface SelectCategory {
46
46
  */
47
47
  export interface SelectCategoryValue {
48
48
  count: number;
49
- key: CategoryKey;
49
+ key: CategoryValueKey;
50
50
  label: string;
51
51
  selected: boolean;
52
52
  }
@@ -64,7 +64,7 @@ export interface SelectCategoryValueView {
64
64
  */
65
65
  export interface SelectCategoryView {
66
66
  isDisabled?: boolean;
67
- key: CategoryValueKey;
67
+ key: CategoryKey;
68
68
  label: string;
69
69
  values: SelectCategoryValueView[];
70
70
  }
@@ -60,7 +60,7 @@ export function getSortMatchesFn(searchTerm) {
60
60
  if (match) {
61
61
  matches.push({ labelRanges: match.ranges, score: match.score, value });
62
62
  }
63
- else {
63
+ else if (typeof value.key === "string") {
64
64
  match = matchString(value.key || "");
65
65
  if (match)
66
66
  matches.push({ score: match.score, value });
@@ -2,7 +2,7 @@ import { VariableSizeListProps as ListProps } from "react-window";
2
2
  import { CategoryKey } from "../../../../common/entities";
3
3
  import { OnFilterFn } from "../../../../hooks/useCategoryFilter";
4
4
  import { FilterMenuSearchMatch } from "../../common/entities";
5
- export type ItemSizeByItemKey = Map<string, number>;
5
+ export type ItemSizeByItemKey = Map<unknown, number>;
6
6
  export interface VariableSizeListProps {
7
7
  categoryKey: CategoryKey;
8
8
  categorySection?: string;
@@ -7,7 +7,7 @@ interface Props {
7
7
  categorySection?: string;
8
8
  matchedItem: FilterMenuSearchMatch;
9
9
  onFilter: OnFilterFn;
10
- onUpdateItemSizeByItemKey: (itemKey: string, itemSize: number) => void;
10
+ onUpdateItemSizeByItemKey: (itemKey: unknown, itemSize: number) => void;
11
11
  style: CSSProperties;
12
12
  }
13
13
  export default function VariableSizeListItem({ categoryKey, categorySection, matchedItem, onFilter, onUpdateItemSizeByItemKey, style, }: Props): JSX.Element;
@@ -42,7 +42,7 @@ export function buildCategoryViews(columns, columnFilters) {
42
42
  const values = [...getFacetedUniqueValues()].map(([value, count]) => ({
43
43
  count,
44
44
  key: value,
45
- label: value,
45
+ label: String(value ?? ""),
46
46
  selected: false, // Selected state updated in reducer.
47
47
  }));
48
48
  categoryViews.push({
@@ -262,7 +262,7 @@ export interface TrackFilterAppliedPayload {
262
262
  searchTerm: string;
263
263
  section: string;
264
264
  selected: boolean;
265
- value: string;
265
+ value: unknown;
266
266
  }
267
267
  /**
268
268
  * Filter applied tracking function
@@ -158,7 +158,11 @@ function isCategoryAcceptListed(category, categoryConfigs) {
158
158
  * @returns Number indicating sort precedence of cv0 vs cv1.
159
159
  */
160
160
  function sortCategoryValueViews(cvv0, cvv1) {
161
- return COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
161
+ return !cvv0.label
162
+ ? 1
163
+ : !cvv1.label
164
+ ? -1
165
+ : COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
162
166
  }
163
167
  /**
164
168
  * Sort category views by display label, ascending.
@@ -96,8 +96,7 @@ function fileManifestReducer(state, action) {
96
96
  // Updates selected file manifest filters with given selected category value.
97
97
  case FileManifestActionKind.UpdateFilter: {
98
98
  // Build next filter state.
99
- const filters = buildNextFilterState(state.filters, payload.categoryKey, getFilterParameterValue(payload.selectedValue), // TODO CategoryValueKey may be boolean or null.
100
- payload.selected);
99
+ const filters = buildNextFilterState(state.filters, payload.categoryKey, getFilterParameterValue(payload.selectedValue), payload.selected);
101
100
  // Get file summary filters.
102
101
  const fileSummaryFilters = buildNextFileSummaryFilterState(filters, state.fileSummaryFacetName);
103
102
  return {
@@ -140,8 +139,7 @@ function buildNextFileSummaryFilterState(filters, facetName) {
140
139
  * @returns all terms for the given category.
141
140
  */
142
141
  function getFileFacetTerms(fileFacet) {
143
- return fileFacet.terms.map((term) => getFilterParameterValue(term.name) // TODO CategoryValueKey may be boolean or null.
144
- );
142
+ return fileFacet.terms.map((term) => getFilterParameterValue(term.name));
145
143
  }
146
144
  /**
147
145
  * Build new set of selected filters on de/select of filter category.
@@ -7,15 +7,15 @@ import { CategoryKeyLabel } from "./entities";
7
7
  */
8
8
  export declare function mapCategoryKeyLabel(CATEGORY_KEY: Record<string, string>, CATEGORY_LABEL: Record<string, string>): CategoryKeyLabel;
9
9
  /**
10
- * Sanitizes a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
11
- * @param str - String to sanitize.
10
+ * Sanitizes a value to a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
11
+ * @param value - Value to sanitize.
12
12
  * @returns the string or sanitized string value.
13
13
  */
14
- export declare function sanitizeString(str: string): string;
14
+ export declare function sanitizeString(value: unknown): string;
15
15
  /**
16
- * Sanitizes a string array for display i.e. any string element within the string array that is an empty, null or
16
+ * Sanitizes array elements to strings for display i.e. any element within the string array that is an empty, null or
17
17
  * undefined value is sanitized to "Unspecified".
18
- * @param strArray - String array to sanitize.
18
+ * @param array - Array to sanitize.
19
19
  * @returns the string array, sanitized.
20
20
  */
21
- export declare function sanitizeStringArray(strArray: string[]): string[];
21
+ export declare function sanitizeStringArray(array: unknown[]): string[];
@@ -13,27 +13,27 @@ export function mapCategoryKeyLabel(CATEGORY_KEY, CATEGORY_LABEL) {
13
13
  return categoryKeyLabel;
14
14
  }
15
15
  /**
16
- * Sanitizes a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
17
- * @param str - String to sanitize.
16
+ * Sanitizes a value to a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
17
+ * @param value - Value to sanitize.
18
18
  * @returns the string or sanitized string value.
19
19
  */
20
- export function sanitizeString(str) {
21
- if (str === "" || str === null || str === undefined) {
20
+ export function sanitizeString(value) {
21
+ if (value === "" || value === null || value === undefined) {
22
22
  return "Unspecified";
23
23
  }
24
24
  else {
25
- return str;
25
+ return String(value);
26
26
  }
27
27
  }
28
28
  /**
29
- * Sanitizes a string array for display i.e. any string element within the string array that is an empty, null or
29
+ * Sanitizes array elements to strings for display i.e. any element within the string array that is an empty, null or
30
30
  * undefined value is sanitized to "Unspecified".
31
- * @param strArray - String array to sanitize.
31
+ * @param array - Array to sanitize.
32
32
  * @returns the string array, sanitized.
33
33
  */
34
- export function sanitizeStringArray(strArray) {
35
- if (!strArray || strArray.length === 0) {
34
+ export function sanitizeStringArray(array) {
35
+ if (!array || array.length === 0) {
36
36
  return ["Unspecified"];
37
37
  }
38
- return strArray.map(sanitizeString);
38
+ return array.map(sanitizeString);
39
39
  }
@@ -72,7 +72,7 @@ export const ExploreView = (props) => {
72
72
  if (selected) {
73
73
  track(EVENT_NAME.FILTER_SELECTED, {
74
74
  [EVENT_PARAM.FILTER_NAME]: categoryKey,
75
- [EVENT_PARAM.FILTER_VALUE]: selectedCategoryValue,
75
+ [EVENT_PARAM.FILTER_VALUE]: String(selectedCategoryValue),
76
76
  });
77
77
  }
78
78
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@databiosphere/findable-ui",
3
- "version": "17.0.0",
3
+ "version": "18.0.0",
4
4
  "description": "",
5
5
  "scripts": {
6
6
  "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
@@ -131,7 +131,7 @@ export function transformTermFacets(
131
131
  categoryValues.push({
132
132
  count: 0,
133
133
  key: term,
134
- label: term ?? LABEL.UNSPECIFIED,
134
+ label: String(term ?? LABEL.UNSPECIFIED),
135
135
  selected: false, // Selected state updated in filter hook
136
136
  });
137
137
  }
@@ -5,7 +5,7 @@ import { ParamValue } from "./filterTransformer";
5
5
  * @param value - Filter value.
6
6
  * @returns filter parameter value.
7
7
  */
8
- export function getFilterParameterValue(value: string): ParamValue {
8
+ export function getFilterParameterValue(value: unknown): ParamValue {
9
9
  if (value === "Unspecified") {
10
10
  return null;
11
11
  }
@@ -15,5 +15,7 @@ export function getFilterParameterValue(value: string): ParamValue {
15
15
  if (value === "false") {
16
16
  return false;
17
17
  }
18
- return value;
18
+ if (typeof value === "string" || typeof value === "boolean") return value;
19
+ if (value === null || value === undefined) return null;
20
+ return String(value);
19
21
  }
@@ -15,7 +15,7 @@ export interface CategoryTag {
15
15
  /**
16
16
  * Category values to be used as keys. For example, "Homo sapiens" or "10X 3' v2 sequencing".
17
17
  */
18
- export type CategoryValueKey = string;
18
+ export type CategoryValueKey = unknown;
19
19
 
20
20
  /**
21
21
  * Set of selected category values.
@@ -53,7 +53,7 @@ export interface SelectCategory {
53
53
  */
54
54
  export interface SelectCategoryValue {
55
55
  count: number;
56
- key: CategoryKey;
56
+ key: CategoryValueKey;
57
57
  label: string; // Allows for displaying null values as "Unspecified"
58
58
  selected: boolean;
59
59
  }
@@ -73,7 +73,7 @@ export interface SelectCategoryValueView {
73
73
  */
74
74
  export interface SelectCategoryView {
75
75
  isDisabled?: boolean;
76
- key: CategoryValueKey;
76
+ key: CategoryKey;
77
77
  label: string;
78
78
  values: SelectCategoryValueView[];
79
79
  }
@@ -74,7 +74,7 @@ export function getSortMatchesFn(
74
74
  let match = matchString(value.label || "");
75
75
  if (match) {
76
76
  matches.push({ labelRanges: match.ranges, score: match.score, value });
77
- } else {
77
+ } else if (typeof value.key === "string") {
78
78
  match = matchString(value.key || "");
79
79
  if (match) matches.push({ score: match.score, value });
80
80
  }
@@ -17,7 +17,7 @@ import { FilterMenuSearchMatch } from "../../common/entities";
17
17
  import { List as FilterList } from "../FilterList/filterList.styles";
18
18
  import VariableSizeListItem from "../VariableSizeListItem/variableSizeListItem";
19
19
 
20
- export type ItemSizeByItemKey = Map<string, number>;
20
+ export type ItemSizeByItemKey = Map<unknown, number>;
21
21
 
22
22
  export interface VariableSizeListProps {
23
23
  categoryKey: CategoryKey;
@@ -19,7 +19,7 @@ interface Props {
19
19
  categorySection?: string;
20
20
  matchedItem: FilterMenuSearchMatch;
21
21
  onFilter: OnFilterFn;
22
- onUpdateItemSizeByItemKey: (itemKey: string, itemSize: number) => void;
22
+ onUpdateItemSizeByItemKey: (itemKey: unknown, itemSize: number) => void;
23
23
  style: CSSProperties;
24
24
  }
25
25
 
@@ -88,7 +88,7 @@ export function buildCategoryViews<T extends RowData>(
88
88
  const values = [...getFacetedUniqueValues()].map(([value, count]) => ({
89
89
  count,
90
90
  key: value,
91
- label: value,
91
+ label: String(value ?? ""),
92
92
  selected: false, // Selected state updated in reducer.
93
93
  }));
94
94
  categoryViews.push({
@@ -324,7 +324,7 @@ export interface TrackFilterAppliedPayload {
324
324
  searchTerm: string;
325
325
  section: string;
326
326
  selected: boolean;
327
- value: string;
327
+ value: unknown;
328
328
  }
329
329
 
330
330
  /**
@@ -273,7 +273,11 @@ function sortCategoryValueViews(
273
273
  cvv0: SelectCategoryValueView,
274
274
  cvv1: SelectCategoryValueView
275
275
  ): number {
276
- return COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
276
+ return !cvv0.label
277
+ ? 1
278
+ : !cvv1.label
279
+ ? -1
280
+ : COLLATOR_CASE_INSENSITIVE.compare(cvv0.label, cvv1.label);
277
281
  }
278
282
 
279
283
  /**
@@ -70,7 +70,7 @@ function bindFacets(
70
70
  function bindFacetTerms(
71
71
  facetName: string,
72
72
  responseTerms: AzulTerm[],
73
- searchTermNames: string[]
73
+ searchTermNames: unknown[]
74
74
  ): Term[] {
75
75
  return responseTerms.reduce((accum: Term[], responseTerm) => {
76
76
  // Default term name to "Unspecified" if term name is null.
@@ -203,7 +203,7 @@ export function isFacetTermSelected(
203
203
  function listFacetSearchTermNames(
204
204
  facetName: string,
205
205
  searchTermsBySearchKey: SelectedSearchTermsBySearchKey
206
- ): string[] {
206
+ ): unknown[] {
207
207
  return [...(searchTermsBySearchKey.get(facetName) ?? [])];
208
208
  }
209
209
 
@@ -262,7 +262,7 @@ function fileManifestReducer(
262
262
  const filters = buildNextFilterState(
263
263
  state.filters,
264
264
  payload.categoryKey,
265
- getFilterParameterValue(payload.selectedValue) as unknown as string, // TODO CategoryValueKey may be boolean or null.
265
+ getFilterParameterValue(payload.selectedValue),
266
266
  payload.selected
267
267
  );
268
268
  // Get file summary filters.
@@ -322,9 +322,7 @@ function buildNextFileSummaryFilterState(
322
322
  * @returns all terms for the given category.
323
323
  */
324
324
  function getFileFacetTerms(fileFacet: FileFacet): SelectedFilterValue {
325
- return fileFacet.terms.map(
326
- (term) => getFilterParameterValue(term.name) as unknown as string // TODO CategoryValueKey may be boolean or null.
327
- );
325
+ return fileFacet.terms.map((term) => getFilterParameterValue(term.name));
328
326
  }
329
327
 
330
328
  /**
@@ -19,27 +19,27 @@ export function mapCategoryKeyLabel(
19
19
  }
20
20
 
21
21
  /**
22
- * Sanitizes a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
23
- * @param str - String to sanitize.
22
+ * Sanitizes a value to a string for display i.e. any empty, null or undefined value is sanitized to "Unspecified".
23
+ * @param value - Value to sanitize.
24
24
  * @returns the string or sanitized string value.
25
25
  */
26
- export function sanitizeString(str: string): string {
27
- if (str === "" || str === null || str === undefined) {
26
+ export function sanitizeString(value: unknown): string {
27
+ if (value === "" || value === null || value === undefined) {
28
28
  return "Unspecified";
29
29
  } else {
30
- return str;
30
+ return String(value);
31
31
  }
32
32
  }
33
33
 
34
34
  /**
35
- * Sanitizes a string array for display i.e. any string element within the string array that is an empty, null or
35
+ * Sanitizes array elements to strings for display i.e. any element within the string array that is an empty, null or
36
36
  * undefined value is sanitized to "Unspecified".
37
- * @param strArray - String array to sanitize.
37
+ * @param array - Array to sanitize.
38
38
  * @returns the string array, sanitized.
39
39
  */
40
- export function sanitizeStringArray(strArray: string[]): string[] {
41
- if (!strArray || strArray.length === 0) {
40
+ export function sanitizeStringArray(array: unknown[]): string[] {
41
+ if (!array || array.length === 0) {
42
42
  return ["Unspecified"];
43
43
  }
44
- return strArray.map(sanitizeString);
44
+ return array.map(sanitizeString);
45
45
  }
@@ -114,7 +114,7 @@ export const ExploreView = (props: ExploreViewProps): JSX.Element => {
114
114
  if (selected) {
115
115
  track(EVENT_NAME.FILTER_SELECTED, {
116
116
  [EVENT_PARAM.FILTER_NAME]: categoryKey,
117
- [EVENT_PARAM.FILTER_VALUE]: selectedCategoryValue,
117
+ [EVENT_PARAM.FILTER_VALUE]: String(selectedCategoryValue),
118
118
  });
119
119
  }
120
120
  };