@databiosphere/findable-ui 48.1.0 → 49.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/.github/workflows/release-please.yml +0 -22
- package/.release-please-manifest.json +1 -1
- package/CHANGELOG.md +27 -0
- package/backend/main.py +0 -1
- package/lib/common/categories/config/types.d.ts +2 -1
- package/lib/common/chart/sort/constants.d.ts +5 -0
- package/lib/common/chart/sort/constants.js +9 -0
- package/lib/common/chart/sort/types.d.ts +16 -0
- package/lib/common/chart/sort/types.js +8 -0
- package/lib/common/chart/sort/utils.d.ts +7 -0
- package/lib/common/chart/sort/utils.js +19 -0
- package/lib/common/chart/types.d.ts +5 -0
- package/lib/common/chart/types.js +1 -0
- package/lib/common/entities.d.ts +2 -1
- package/lib/components/Export/components/DownloadCurlCommand/downloadCurlCommand.d.ts +0 -2
- package/lib/components/Export/components/ExportToTerra/exportToTerra.d.ts +0 -2
- package/lib/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/manifestDownloadEntity.d.ts +0 -2
- package/lib/components/Export/components/ManifestDownload/manifestDownload.d.ts +0 -2
- package/lib/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.js +1 -1
- package/lib/components/Index/components/EntityView/components/views/ChartView/chartView.js +2 -1
- package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.js +2 -7
- package/lib/components/Index/components/EntityView/components/views/ChartView/components/Chart/stories/args.js +12 -12
- package/lib/components/Index/components/EntityView/components/views/ChartView/stories/args.js +3 -3
- package/lib/components/Index/components/EntityView/components/views/ChartView/utils.js +1 -1
- package/lib/hooks/useCategoryFilter.js +1 -1
- package/lib/hooks/useFileManifest/common/entities.d.ts +0 -9
- package/lib/hooks/useFileManifest/common/entities.js +1 -9
- package/lib/views/EntityDetailView/entityDetailView.js +2 -2
- package/package.json +1 -1
- package/src/common/categories/config/types.ts +2 -1
- package/src/common/chart/sort/constants.ts +13 -0
- package/src/common/chart/sort/types.ts +22 -0
- package/src/common/chart/sort/utils.ts +22 -0
- package/src/common/chart/types.ts +6 -0
- package/src/common/entities.ts +2 -1
- package/src/components/Export/components/DownloadCurlCommand/downloadCurlCommand.tsx +0 -2
- package/src/components/Export/components/ExportToTerra/exportToTerra.tsx +0 -2
- package/src/components/Export/components/ManifestDownload/components/ManifestDownloadEntity/manifestDownloadEntity.tsx +0 -2
- package/src/components/Export/components/ManifestDownload/manifestDownload.tsx +0 -2
- package/src/components/Filter/components/adapters/tanstack/ColumnFiltersAdapter/utils.ts +1 -1
- package/src/components/Index/components/EntityView/components/views/ChartView/chartView.tsx +8 -2
- package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/hooks/UsePlotOptions/hook.ts +2 -7
- package/src/components/Index/components/EntityView/components/views/ChartView/components/Chart/stories/args.ts +12 -12
- package/src/components/Index/components/EntityView/components/views/ChartView/stories/args.ts +3 -3
- package/src/components/Index/components/EntityView/components/views/ChartView/utils.ts +1 -1
- package/src/hooks/useCategoryFilter.ts +1 -1
- package/src/hooks/useFileManifest/common/entities.ts +0 -11
- package/src/views/EntityDetailView/entityDetailView.tsx +1 -3
- package/tests/chartSortUtils.test.ts +119 -0
|
@@ -44,28 +44,6 @@ jobs:
|
|
|
44
44
|
if: ${{ steps.release.outputs.release_created }}
|
|
45
45
|
run: npx tsc
|
|
46
46
|
|
|
47
|
-
- name: Debug OIDC Token
|
|
48
|
-
if: ${{ steps.release.outputs.release_created }}
|
|
49
|
-
run: |
|
|
50
|
-
echo "=== OIDC Debug Info ==="
|
|
51
|
-
echo "Repository: $GITHUB_REPOSITORY"
|
|
52
|
-
echo "Workflow: $GITHUB_WORKFLOW"
|
|
53
|
-
echo "Job: $GITHUB_JOB"
|
|
54
|
-
echo "Run ID: $GITHUB_RUN_ID"
|
|
55
|
-
echo "Ref: $GITHUB_REF"
|
|
56
|
-
echo "Token URL available: ${{ env.ACTIONS_ID_TOKEN_REQUEST_URL != '' }}"
|
|
57
|
-
echo "=== Requesting OIDC token for npm ==="
|
|
58
|
-
if [ -n "$ACTIONS_ID_TOKEN_REQUEST_URL" ]; then
|
|
59
|
-
if OIDC_RESPONSE=$(curl -sS -H "Authorization: bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \
|
|
60
|
-
"$ACTIONS_ID_TOKEN_REQUEST_URL&audience=npm" 2>/dev/null); then
|
|
61
|
-
echo "✓ OIDC token request succeeded"
|
|
62
|
-
else
|
|
63
|
-
echo "✗ Failed to get OIDC token"
|
|
64
|
-
fi
|
|
65
|
-
else
|
|
66
|
-
echo "✗ ACTIONS_ID_TOKEN_REQUEST_URL is not set - id-token permission may be missing"
|
|
67
|
-
fi
|
|
68
|
-
|
|
69
47
|
- name: Publish to NPM
|
|
70
48
|
if: ${{ steps.release.outputs.release_created }}
|
|
71
49
|
run: npm publish --provenance --access public
|
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,32 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [49.0.0](https://github.com/DataBiosphere/findable-ui/compare/v48.1.0...v49.0.0) (2026-02-17)
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
### ⚠ BREAKING CHANGES
|
|
7
|
+
|
|
8
|
+
* chartview: add configurable bar sort order ([#772](https://github.com/DataBiosphere/findable-ui/issues/772)) (#773)
|
|
9
|
+
* remove unused filemanifesttype prop and type definitions from export components ([#767](https://github.com/DataBiosphere/findable-ui/issues/767)) (#768)
|
|
10
|
+
|
|
11
|
+
### Features
|
|
12
|
+
|
|
13
|
+
* chartview: add configurable bar sort order ([#772](https://github.com/DataBiosphere/findable-ui/issues/772)) ([#773](https://github.com/DataBiosphere/findable-ui/issues/773)) ([bea776a](https://github.com/DataBiosphere/findable-ui/commit/bea776a987a612d30a0010f29af128946f4aad48))
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* remove unused filemanifesttype prop and type definitions from export components ([#767](https://github.com/DataBiosphere/findable-ui/issues/767)) ([#768](https://github.com/DataBiosphere/findable-ui/issues/768)) ([4da929f](https://github.com/DataBiosphere/findable-ui/commit/4da929fcfd3acaccdb60f269bbffa8be033fdec3))
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
### Chores
|
|
22
|
+
|
|
23
|
+
* remove debug code ([#762](https://github.com/DataBiosphere/findable-ui/issues/762)) ([#765](https://github.com/DataBiosphere/findable-ui/issues/765)) ([6a6b8f5](https://github.com/DataBiosphere/findable-ui/commit/6a6b8f5087bf972397fa4104f946b41eae03a0da))
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
### Code Refactoring
|
|
27
|
+
|
|
28
|
+
* render null instead of empty fragment when hideTabs is true ([#770](https://github.com/DataBiosphere/findable-ui/issues/770)) ([#771](https://github.com/DataBiosphere/findable-ui/issues/771)) ([62733b7](https://github.com/DataBiosphere/findable-ui/commit/62733b7fb271fa6be4a29b7c7d545272a1c3e9ef))
|
|
29
|
+
|
|
3
30
|
## [48.1.0](https://github.com/DataBiosphere/findable-ui/compare/v48.0.0...v48.1.0) (2026-01-11)
|
|
4
31
|
|
|
5
32
|
|
package/backend/main.py
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Chart } from "../../chart/types";
|
|
1
2
|
import { CategoryKey, DataDictionaryAnnotation, SelectCategoryValueView } from "../../entities";
|
|
2
3
|
import { RangeViewKind } from "../views/range/types";
|
|
3
4
|
import { SelectViewKind } from "../views/select/types";
|
|
@@ -23,6 +24,6 @@ export interface RangeCategoryConfig extends CommonCategoryConfig, RangeViewKind
|
|
|
23
24
|
* Select category config.
|
|
24
25
|
*/
|
|
25
26
|
export interface SelectCategoryConfig extends CommonCategoryConfig, SelectViewKind {
|
|
26
|
-
|
|
27
|
+
chart?: Chart;
|
|
27
28
|
mapSelectCategoryValue?: (selectCategoryValue: SelectCategoryValueView) => SelectCategoryValueView;
|
|
28
29
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { sortCategoryValueViewsAlpha, sortCategoryValueViewsCount, } from "../../filters/sort/models/utils";
|
|
2
|
+
import { CHART_SORT } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Map of chart sort options to their corresponding sort functions.
|
|
5
|
+
*/
|
|
6
|
+
export const CHART_SORT_FN = {
|
|
7
|
+
[CHART_SORT.ALPHA]: sortCategoryValueViewsAlpha,
|
|
8
|
+
[CHART_SORT.COUNT]: sortCategoryValueViewsCount,
|
|
9
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { SelectCategoryValueView } from "../../entities";
|
|
2
|
+
/**
|
|
3
|
+
* Chart sorting options for select categories.
|
|
4
|
+
*/
|
|
5
|
+
export declare enum CHART_SORT {
|
|
6
|
+
ALPHA = "ALPHA",
|
|
7
|
+
COUNT = "COUNT"
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Sorting function type for select category values.
|
|
11
|
+
*/
|
|
12
|
+
export type ChartSortFn = (a: SelectCategoryValueView, b: SelectCategoryValueView) => number;
|
|
13
|
+
/**
|
|
14
|
+
* Chart sort options - either a preset (ALPHA, COUNT) or a custom sort function.
|
|
15
|
+
*/
|
|
16
|
+
export type ChartSortOptions = CHART_SORT | ChartSortFn;
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { ChartSortOptions, ChartSortFn } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Resolves chart sort options to a sorting function.
|
|
4
|
+
* @param chartSortOptions - Chart sort option (ALPHA, COUNT, or custom function).
|
|
5
|
+
* @returns Sorting function to use for chart data.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getChartSortFn(chartSortOptions?: ChartSortOptions): ChartSortFn;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { CHART_SORT_FN } from "./constants";
|
|
2
|
+
import { CHART_SORT } from "./types";
|
|
3
|
+
/**
|
|
4
|
+
* Resolves chart sort options to a sorting function.
|
|
5
|
+
* @param chartSortOptions - Chart sort option (ALPHA, COUNT, or custom function).
|
|
6
|
+
* @returns Sorting function to use for chart data.
|
|
7
|
+
*/
|
|
8
|
+
export function getChartSortFn(chartSortOptions) {
|
|
9
|
+
// Default to COUNT sort if not specified.
|
|
10
|
+
if (!chartSortOptions) {
|
|
11
|
+
return CHART_SORT_FN[CHART_SORT.COUNT];
|
|
12
|
+
}
|
|
13
|
+
// If it's a custom function, return it directly.
|
|
14
|
+
if (typeof chartSortOptions === "function") {
|
|
15
|
+
return chartSortOptions;
|
|
16
|
+
}
|
|
17
|
+
// Otherwise, look up the function from the map.
|
|
18
|
+
return CHART_SORT_FN[chartSortOptions];
|
|
19
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/lib/common/entities.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RowData, TableOptions } from "@tanstack/react-table";
|
|
2
|
+
import { Chart } from "./chart/types";
|
|
2
3
|
/**
|
|
3
4
|
* Model of a value of a metadata class.
|
|
4
5
|
*/
|
|
@@ -133,7 +134,7 @@ export interface SelectCategoryValueView {
|
|
|
133
134
|
*/
|
|
134
135
|
export interface SelectCategoryView {
|
|
135
136
|
annotation?: DataDictionaryAnnotation;
|
|
136
|
-
|
|
137
|
+
chart?: Chart;
|
|
137
138
|
isDisabled?: boolean;
|
|
138
139
|
key: CategoryKey;
|
|
139
140
|
label: string;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { JSX, ElementType } from "react";
|
|
2
2
|
import { Filters } from "../../../../common/entities";
|
|
3
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
4
3
|
import { FileManifestState } from "../../../../providers/fileManifestState";
|
|
5
4
|
import { FormFacet, ManifestDownloadFormat } from "../../common/entities";
|
|
6
5
|
interface DownloadCurlCommandProps {
|
|
@@ -8,7 +7,6 @@ interface DownloadCurlCommandProps {
|
|
|
8
7
|
DownloadCurlStart: ElementType;
|
|
9
8
|
DownloadCurlSuccess: ElementType;
|
|
10
9
|
fileManifestState: FileManifestState;
|
|
11
|
-
fileManifestType: FileManifestType;
|
|
12
10
|
fileSummaryFacetName: string;
|
|
13
11
|
filters: Filters;
|
|
14
12
|
formFacet: FormFacet;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { JSX, ElementType } from "react";
|
|
2
2
|
import { Filters } from "../../../../common/entities";
|
|
3
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
4
3
|
import { FileManifestState } from "../../../../providers/fileManifestState";
|
|
5
4
|
import { FormFacet, ManifestDownloadFormat } from "../../common/entities";
|
|
6
5
|
export interface ExportToTerraProps {
|
|
@@ -8,7 +7,6 @@ export interface ExportToTerraProps {
|
|
|
8
7
|
ExportToTerraStart: ElementType;
|
|
9
8
|
ExportToTerraSuccess: ElementType;
|
|
10
9
|
fileManifestState: FileManifestState;
|
|
11
|
-
fileManifestType: FileManifestType;
|
|
12
10
|
fileSummaryFacetName: string;
|
|
13
11
|
filters: Filters;
|
|
14
12
|
formFacet: FormFacet;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
2
|
import { Filters } from "../../../../../../common/entities";
|
|
3
|
-
import { FileManifestType } from "../../../../../../hooks/useFileManifest/common/entities";
|
|
4
3
|
import { ManifestDownloadFormat } from "../../../../common/entities";
|
|
5
4
|
export interface ManifestDownloadEntityProps {
|
|
6
|
-
fileManifestType: FileManifestType;
|
|
7
5
|
filters: Filters;
|
|
8
6
|
manifestDownloadFormat?: ManifestDownloadFormat;
|
|
9
7
|
metadataFilters: Filters;
|
|
@@ -1,11 +1,9 @@
|
|
|
1
1
|
import { JSX, ElementType } from "react";
|
|
2
2
|
import { Filters } from "../../../../common/entities";
|
|
3
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
4
3
|
import { FileManifestState } from "../../../../providers/fileManifestState";
|
|
5
4
|
import { FormFacet, ManifestDownloadFormat } from "../../common/entities";
|
|
6
5
|
export interface ManifestDownloadProps {
|
|
7
6
|
fileManifestState: FileManifestState;
|
|
8
|
-
fileManifestType: FileManifestType;
|
|
9
7
|
fileSummaryFacetName: string;
|
|
10
8
|
filters: Filters;
|
|
11
9
|
formFacet: FormFacet;
|
|
@@ -145,7 +145,7 @@ function mapColumnToSelectCategoryView(column, filterSort, categoryConfig) {
|
|
|
145
145
|
const values = mapColumnToSelectCategoryValueView(column, filterSort).map(categoryConfig?.mapSelectCategoryValue || getSelectCategoryValue);
|
|
146
146
|
return {
|
|
147
147
|
annotation: undefined,
|
|
148
|
-
|
|
148
|
+
chart: undefined,
|
|
149
149
|
isDisabled,
|
|
150
150
|
key: column.id,
|
|
151
151
|
label: getColumnHeader(column),
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { Typography } from "@mui/material";
|
|
3
3
|
import { Fragment } from "react";
|
|
4
|
+
import { getChartSortFn } from "../../../../../../../common/chart/sort/utils";
|
|
4
5
|
import { TYPOGRAPHY_PROPS } from "../../../../../../../styles/common/mui/typography";
|
|
5
6
|
import { Loading, LOADING_PANEL_STYLE, } from "../../../../../../Loading/loading";
|
|
6
7
|
import { StyledToolbar } from "../../../../../../Table/components/TableToolbar/tableToolbar.styles";
|
|
@@ -12,5 +13,5 @@ export const ChartView = ({ categoryFilters, entityName, loading, testId, }) =>
|
|
|
12
13
|
const { chartViewRef, selectCategoryViews, width } = useChartView(categoryFilters);
|
|
13
14
|
if (selectCategoryViews.length === 0)
|
|
14
15
|
return null;
|
|
15
|
-
return (_jsxs(Fragment, { children: [_jsx(StyledToolbar, { children: _jsx(ViewToggle, {}) }), _jsx(Loading, { appear: false, autoPosition: false, loading: loading, panelStyle: LOADING_PANEL_STYLE.INHERIT }), _jsx(StyledGrid, { "data-testid": testId, ref: chartViewRef, children: selectCategoryViews.map(({ key, label, values }) => (_jsxs(StyledGridPaperSection, { children: [_jsxs(Typography, { variant: TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL, children: [entityName, " by ", label] }), _jsx(Chart, { selectCategoryValueViews: values, width: width })] }, key))) })] }));
|
|
16
|
+
return (_jsxs(Fragment, { children: [_jsx(StyledToolbar, { children: _jsx(ViewToggle, {}) }), _jsx(Loading, { appear: false, autoPosition: false, loading: loading, panelStyle: LOADING_PANEL_STYLE.INHERIT }), _jsx(StyledGrid, { "data-testid": testId, ref: chartViewRef, children: selectCategoryViews.map(({ chart, key, label, values }) => (_jsxs(StyledGridPaperSection, { children: [_jsxs(Typography, { variant: TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL, children: [entityName, " by ", label] }), _jsx(Chart, { selectCategoryValueViews: [...values].sort(getChartSortFn(chart?.sortBy)), width: width })] }, key))) })] }));
|
|
16
17
|
};
|
|
@@ -1,14 +1,9 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
|
-
import { sortCategoryValueViewsCount } from "../../../../../../../../../../../common/filters/sort/models/utils";
|
|
3
2
|
import { getPlotOptions } from "../../barX/plot";
|
|
4
3
|
import { getCategoryTotalCount } from "../../barX/utils";
|
|
5
4
|
export const usePlotOptions = (selectCategoryValueViews, width, barCount) => {
|
|
6
|
-
//
|
|
7
|
-
const data = selectCategoryValueViews
|
|
8
|
-
// Sort the category values by count and label.
|
|
9
|
-
.sort(sortCategoryValueViewsCount)
|
|
10
|
-
// Slice the category values to the number of bars to display.
|
|
11
|
-
.slice(0, barCount);
|
|
5
|
+
// Slice the category values to the number of bars to display.
|
|
6
|
+
const data = selectCategoryValueViews.slice(0, barCount);
|
|
12
7
|
// Build the plot options.
|
|
13
8
|
const options = useMemo(() => getPlotOptions(data, getCategoryTotalCount(selectCategoryValueViews), width), [data, selectCategoryValueViews, width]);
|
|
14
9
|
return { options };
|
|
@@ -12,12 +12,6 @@ export const CHART_ARGS = {
|
|
|
12
12
|
label: "male",
|
|
13
13
|
selected: false,
|
|
14
14
|
},
|
|
15
|
-
{
|
|
16
|
-
count: 240,
|
|
17
|
-
key: "mixed",
|
|
18
|
-
label: "mixed",
|
|
19
|
-
selected: false,
|
|
20
|
-
},
|
|
21
15
|
{
|
|
22
16
|
count: 78715,
|
|
23
17
|
key: "unknown",
|
|
@@ -30,6 +24,12 @@ export const CHART_ARGS = {
|
|
|
30
24
|
label: "Unspecified",
|
|
31
25
|
selected: false,
|
|
32
26
|
},
|
|
27
|
+
{
|
|
28
|
+
count: 240,
|
|
29
|
+
key: "mixed",
|
|
30
|
+
label: "mixed",
|
|
31
|
+
selected: false,
|
|
32
|
+
},
|
|
33
33
|
],
|
|
34
34
|
width: 800,
|
|
35
35
|
};
|
|
@@ -47,12 +47,6 @@ export const SELECT_CHART_ARGS = {
|
|
|
47
47
|
label: "male",
|
|
48
48
|
selected: true,
|
|
49
49
|
},
|
|
50
|
-
{
|
|
51
|
-
count: 240,
|
|
52
|
-
key: "mixed",
|
|
53
|
-
label: "mixed",
|
|
54
|
-
selected: false,
|
|
55
|
-
},
|
|
56
50
|
{
|
|
57
51
|
count: 78715,
|
|
58
52
|
key: "unknown",
|
|
@@ -65,6 +59,12 @@ export const SELECT_CHART_ARGS = {
|
|
|
65
59
|
label: "Unspecified",
|
|
66
60
|
selected: true,
|
|
67
61
|
},
|
|
62
|
+
{
|
|
63
|
+
count: 240,
|
|
64
|
+
key: "mixed",
|
|
65
|
+
label: "mixed",
|
|
66
|
+
selected: false,
|
|
67
|
+
},
|
|
68
68
|
],
|
|
69
69
|
width: 800,
|
|
70
70
|
};
|
package/lib/components/Index/components/EntityView/components/views/ChartView/stories/args.js
CHANGED
|
@@ -3,7 +3,7 @@ export const CHART_VIEW_ARGS = {
|
|
|
3
3
|
{
|
|
4
4
|
categoryViews: [
|
|
5
5
|
{
|
|
6
|
-
|
|
6
|
+
chart: { enable: true },
|
|
7
7
|
key: "biological-sex",
|
|
8
8
|
label: "Biological Sex",
|
|
9
9
|
values: [
|
|
@@ -40,7 +40,7 @@ export const CHART_VIEW_ARGS = {
|
|
|
40
40
|
],
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
|
-
|
|
43
|
+
chart: { enable: true },
|
|
44
44
|
key: "genusSpecies",
|
|
45
45
|
label: "Genus Species",
|
|
46
46
|
values: [
|
|
@@ -71,7 +71,7 @@ export const CHART_VIEW_ARGS = {
|
|
|
71
71
|
],
|
|
72
72
|
},
|
|
73
73
|
{
|
|
74
|
-
|
|
74
|
+
chart: { enable: false },
|
|
75
75
|
key: "pairedEnd",
|
|
76
76
|
label: "Paired End",
|
|
77
77
|
values: [
|
|
@@ -8,7 +8,7 @@ export function getSelectCategoryViews(categoryFilters) {
|
|
|
8
8
|
return categoryFilters
|
|
9
9
|
.flatMap(({ categoryViews }) => categoryViews)
|
|
10
10
|
.filter(isSelectCategoryView)
|
|
11
|
-
.filter(({
|
|
11
|
+
.filter(({ chart }) => chart?.enable !== false)
|
|
12
12
|
.filter(({ values }) => values.length > 0);
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
@@ -35,7 +35,7 @@ function buildCategoryView(selectCategory, selectCategoryValueViews, categoryCon
|
|
|
35
35
|
const mapSelectCategoryValue = selectCategoryConfig?.mapSelectCategoryValue || getSelectCategoryValue;
|
|
36
36
|
return {
|
|
37
37
|
annotation: selectCategoryConfig?.annotation,
|
|
38
|
-
|
|
38
|
+
chart: selectCategoryConfig?.chart,
|
|
39
39
|
isDisabled: false,
|
|
40
40
|
key: selectCategory.key,
|
|
41
41
|
label: getCategoryLabel(selectCategory.key, selectCategoryConfig),
|
|
@@ -29,15 +29,6 @@ export interface FileFacet {
|
|
|
29
29
|
termsByName: TermsByName;
|
|
30
30
|
total: number;
|
|
31
31
|
}
|
|
32
|
-
export declare enum FILE_MANIFEST_TYPE {
|
|
33
|
-
BULK_DOWNLOAD = "BULK_DOWNLOAD",
|
|
34
|
-
DOWNLOAD_MANIFEST = "DOWNLOAD_MANIFEST",
|
|
35
|
-
ENTITY_BULK_DOWNLOAD = "ENTITY_BULK_DOWNLOAD",
|
|
36
|
-
ENTITY_DOWNLOAD_MANIFEST = "ENTITY_DOWNLOAD_MANIFEST",
|
|
37
|
-
ENTITY_EXPORT_TO_TERRA = "ENTITY_EXPORT_TO_TERRA",
|
|
38
|
-
EXPORT_TO_TERRA = "EXPORT_TO_TERRA"
|
|
39
|
-
}
|
|
40
|
-
export type FileManifestType = FILE_MANIFEST_TYPE;
|
|
41
32
|
export type SelectedSearchTermsBySearchKey = Map<CategoryKey, Set<CategoryValueKey>>;
|
|
42
33
|
/**
|
|
43
34
|
* Model of an individual facet value. For example, the term "Homo Sapiens" contained in the facet "Species".
|
|
@@ -1,9 +1 @@
|
|
|
1
|
-
export
|
|
2
|
-
(function (FILE_MANIFEST_TYPE) {
|
|
3
|
-
FILE_MANIFEST_TYPE["BULK_DOWNLOAD"] = "BULK_DOWNLOAD";
|
|
4
|
-
FILE_MANIFEST_TYPE["DOWNLOAD_MANIFEST"] = "DOWNLOAD_MANIFEST";
|
|
5
|
-
FILE_MANIFEST_TYPE["ENTITY_BULK_DOWNLOAD"] = "ENTITY_BULK_DOWNLOAD";
|
|
6
|
-
FILE_MANIFEST_TYPE["ENTITY_DOWNLOAD_MANIFEST"] = "ENTITY_DOWNLOAD_MANIFEST";
|
|
7
|
-
FILE_MANIFEST_TYPE["ENTITY_EXPORT_TO_TERRA"] = "ENTITY_EXPORT_TO_TERRA";
|
|
8
|
-
FILE_MANIFEST_TYPE["EXPORT_TO_TERRA"] = "EXPORT_TO_TERRA";
|
|
9
|
-
})(FILE_MANIFEST_TYPE || (FILE_MANIFEST_TYPE = {}));
|
|
1
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsx as _jsx,
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
2
|
import Head from "next/head";
|
|
3
3
|
import { useRouter } from "next/router";
|
|
4
4
|
import { Fragment } from "react";
|
|
@@ -48,5 +48,5 @@ export const EntityDetailView = (props) => {
|
|
|
48
48
|
const onTabChange = (tabValue) => {
|
|
49
49
|
push(`/${entityRoute}/${uuid}/${tabValue}`);
|
|
50
50
|
};
|
|
51
|
-
return (_jsxs(Fragment, { children: [title && (_jsx(Head, { children: _jsx("title", { children: title }) })), _jsx(DetailView, { isDetailOverview: isDetailOverview, mainColumn: _jsx(ComponentCreator, { components: mainColumn, response: response }), sideColumn: sideColumn ? (_jsx(ComponentCreator, { components: sideColumn, response: response })) : undefined, Tabs: hideTabs ?
|
|
51
|
+
return (_jsxs(Fragment, { children: [title && (_jsx(Head, { children: _jsx("title", { children: title }) })), _jsx(DetailView, { isDetailOverview: isDetailOverview, mainColumn: _jsx(ComponentCreator, { components: mainColumn, response: response }), sideColumn: sideColumn ? (_jsx(ComponentCreator, { components: sideColumn, response: response })) : undefined, Tabs: hideTabs ? null : (_jsx(Tabs, { onTabChange: onTabChange, tabs: tabs, value: tabRoute })), top: _jsx(ComponentCreator, { components: top, response: response }) })] }));
|
|
52
52
|
};
|
package/package.json
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Chart } from "../../chart/types";
|
|
1
2
|
import {
|
|
2
3
|
CategoryKey,
|
|
3
4
|
DataDictionaryAnnotation,
|
|
@@ -33,7 +34,7 @@ export interface RangeCategoryConfig
|
|
|
33
34
|
*/
|
|
34
35
|
export interface SelectCategoryConfig
|
|
35
36
|
extends CommonCategoryConfig, SelectViewKind {
|
|
36
|
-
|
|
37
|
+
chart?: Chart;
|
|
37
38
|
mapSelectCategoryValue?: (
|
|
38
39
|
selectCategoryValue: SelectCategoryValueView,
|
|
39
40
|
) => SelectCategoryValueView;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
sortCategoryValueViewsAlpha,
|
|
3
|
+
sortCategoryValueViewsCount,
|
|
4
|
+
} from "../../filters/sort/models/utils";
|
|
5
|
+
import { CHART_SORT, ChartSortFn } from "./types";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Map of chart sort options to their corresponding sort functions.
|
|
9
|
+
*/
|
|
10
|
+
export const CHART_SORT_FN: Record<CHART_SORT, ChartSortFn> = {
|
|
11
|
+
[CHART_SORT.ALPHA]: sortCategoryValueViewsAlpha,
|
|
12
|
+
[CHART_SORT.COUNT]: sortCategoryValueViewsCount,
|
|
13
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { SelectCategoryValueView } from "../../entities";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Chart sorting options for select categories.
|
|
5
|
+
*/
|
|
6
|
+
export enum CHART_SORT {
|
|
7
|
+
ALPHA = "ALPHA",
|
|
8
|
+
COUNT = "COUNT",
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Sorting function type for select category values.
|
|
13
|
+
*/
|
|
14
|
+
export type ChartSortFn = (
|
|
15
|
+
a: SelectCategoryValueView,
|
|
16
|
+
b: SelectCategoryValueView,
|
|
17
|
+
) => number;
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Chart sort options - either a preset (ALPHA, COUNT) or a custom sort function.
|
|
21
|
+
*/
|
|
22
|
+
export type ChartSortOptions = CHART_SORT | ChartSortFn;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { CHART_SORT_FN } from "./constants";
|
|
2
|
+
import { CHART_SORT, ChartSortOptions, ChartSortFn } from "./types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Resolves chart sort options to a sorting function.
|
|
6
|
+
* @param chartSortOptions - Chart sort option (ALPHA, COUNT, or custom function).
|
|
7
|
+
* @returns Sorting function to use for chart data.
|
|
8
|
+
*/
|
|
9
|
+
export function getChartSortFn(
|
|
10
|
+
chartSortOptions?: ChartSortOptions,
|
|
11
|
+
): ChartSortFn {
|
|
12
|
+
// Default to COUNT sort if not specified.
|
|
13
|
+
if (!chartSortOptions) {
|
|
14
|
+
return CHART_SORT_FN[CHART_SORT.COUNT];
|
|
15
|
+
}
|
|
16
|
+
// If it's a custom function, return it directly.
|
|
17
|
+
if (typeof chartSortOptions === "function") {
|
|
18
|
+
return chartSortOptions;
|
|
19
|
+
}
|
|
20
|
+
// Otherwise, look up the function from the map.
|
|
21
|
+
return CHART_SORT_FN[chartSortOptions];
|
|
22
|
+
}
|
package/src/common/entities.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { RowData, TableOptions } from "@tanstack/react-table";
|
|
2
|
+
import { Chart } from "./chart/types";
|
|
2
3
|
|
|
3
4
|
/**
|
|
4
5
|
* Model of a value of a metadata class.
|
|
@@ -152,7 +153,7 @@ export interface SelectCategoryValueView {
|
|
|
152
153
|
*/
|
|
153
154
|
export interface SelectCategoryView {
|
|
154
155
|
annotation?: DataDictionaryAnnotation;
|
|
155
|
-
|
|
156
|
+
chart?: Chart;
|
|
156
157
|
isDisabled?: boolean;
|
|
157
158
|
key: CategoryKey;
|
|
158
159
|
label: string;
|
|
@@ -2,7 +2,6 @@ import { JSX, ElementType, useState } from "react";
|
|
|
2
2
|
import { MANIFEST_DOWNLOAD_FORMAT } from "../../../../apis/azul/common/entities";
|
|
3
3
|
import { Filters } from "../../../../common/entities";
|
|
4
4
|
import { useExploreState } from "../../../../hooks/useExploreState";
|
|
5
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
6
5
|
import { useFileManifest } from "../../../../hooks/useFileManifest/useFileManifest";
|
|
7
6
|
import { useFileManifestFileCount } from "../../../../hooks/useFileManifest/useFileManifestFileCount";
|
|
8
7
|
import {
|
|
@@ -26,7 +25,6 @@ interface DownloadCurlCommandProps {
|
|
|
26
25
|
DownloadCurlStart: ElementType;
|
|
27
26
|
DownloadCurlSuccess: ElementType;
|
|
28
27
|
fileManifestState: FileManifestState;
|
|
29
|
-
fileManifestType: FileManifestType;
|
|
30
28
|
fileSummaryFacetName: string;
|
|
31
29
|
filters: Filters; // Initializes bulk download filters.
|
|
32
30
|
formFacet: FormFacet;
|
|
@@ -2,7 +2,6 @@ import { JSX, ElementType } from "react";
|
|
|
2
2
|
import { Filters } from "../../../../common/entities";
|
|
3
3
|
import { useExploreState } from "../../../../hooks/useExploreState";
|
|
4
4
|
import { useExportToTerraResponseURL } from "../../../../hooks/useExportToTerraResponseURL";
|
|
5
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
6
5
|
import { useFileManifest } from "../../../../hooks/useFileManifest/useFileManifest";
|
|
7
6
|
import { useFileManifestFileCount } from "../../../../hooks/useFileManifest/useFileManifestFileCount";
|
|
8
7
|
import { useFileManifestFormat } from "../../../../hooks/useFileManifest/useFileManifestFormat";
|
|
@@ -19,7 +18,6 @@ export interface ExportToTerraProps {
|
|
|
19
18
|
ExportToTerraStart: ElementType;
|
|
20
19
|
ExportToTerraSuccess: ElementType;
|
|
21
20
|
fileManifestState: FileManifestState;
|
|
22
|
-
fileManifestType: FileManifestType;
|
|
23
21
|
fileSummaryFacetName: string;
|
|
24
22
|
filters: Filters; // Initializes export to terra filters.
|
|
25
23
|
formFacet: FormFacet;
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { JSX } from "react";
|
|
2
2
|
import { Filters } from "../../../../../../common/entities";
|
|
3
|
-
import { FileManifestType } from "../../../../../../hooks/useFileManifest/common/entities";
|
|
4
3
|
import { useFileManifest } from "../../../../../../hooks/useFileManifest/useFileManifest";
|
|
5
4
|
import { ManifestDownloadFormat } from "../../../../common/entities";
|
|
6
5
|
import { FileManifestDownload } from "./components/FileManifestDownload/fileManifestDownload";
|
|
7
6
|
import { FileManifestSpreadsheet } from "./components/FileManifestSpreadsheet/fileManifestSpreadsheet";
|
|
8
7
|
|
|
9
8
|
export interface ManifestDownloadEntityProps {
|
|
10
|
-
fileManifestType: FileManifestType;
|
|
11
9
|
filters: Filters; // Initializes manifest download filters.
|
|
12
10
|
manifestDownloadFormat?: ManifestDownloadFormat;
|
|
13
11
|
metadataFilters: Filters; // Metadata filters filters.
|
|
@@ -2,7 +2,6 @@ import { JSX, ElementType } from "react";
|
|
|
2
2
|
import { MANIFEST_DOWNLOAD_FORMAT } from "../../../../apis/azul/common/entities";
|
|
3
3
|
import { Filters } from "../../../../common/entities";
|
|
4
4
|
import { useExploreState } from "../../../../hooks/useExploreState";
|
|
5
|
-
import { FileManifestType } from "../../../../hooks/useFileManifest/common/entities";
|
|
6
5
|
import { useFileManifest } from "../../../../hooks/useFileManifest/useFileManifest";
|
|
7
6
|
import { useFileManifestFileCount } from "../../../../hooks/useFileManifest/useFileManifestFileCount";
|
|
8
7
|
import {
|
|
@@ -18,7 +17,6 @@ import { ManifestDownloadReady } from "./components/ManifestDownloadReady/manife
|
|
|
18
17
|
|
|
19
18
|
export interface ManifestDownloadProps {
|
|
20
19
|
fileManifestState: FileManifestState;
|
|
21
|
-
fileManifestType: FileManifestType;
|
|
22
20
|
fileSummaryFacetName: string;
|
|
23
21
|
filters: Filters; // Initializes manifest download filters.
|
|
24
22
|
formFacet: FormFacet;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Typography } from "@mui/material";
|
|
2
2
|
import { Fragment, JSX } from "react";
|
|
3
|
+
import { getChartSortFn } from "../../../../../../../common/chart/sort/utils";
|
|
3
4
|
import { TYPOGRAPHY_PROPS } from "../../../../../../../styles/common/mui/typography";
|
|
4
5
|
import {
|
|
5
6
|
Loading,
|
|
@@ -33,12 +34,17 @@ export const ChartView = ({
|
|
|
33
34
|
panelStyle={LOADING_PANEL_STYLE.INHERIT}
|
|
34
35
|
/>
|
|
35
36
|
<StyledGrid data-testid={testId} ref={chartViewRef}>
|
|
36
|
-
{selectCategoryViews.map(({ key, label, values }) => (
|
|
37
|
+
{selectCategoryViews.map(({ chart, key, label, values }) => (
|
|
37
38
|
<StyledGridPaperSection key={key}>
|
|
38
39
|
<Typography variant={TYPOGRAPHY_PROPS.VARIANT.HEADING_SMALL}>
|
|
39
40
|
{entityName} by {label}
|
|
40
41
|
</Typography>
|
|
41
|
-
<Chart
|
|
42
|
+
<Chart
|
|
43
|
+
selectCategoryValueViews={[...values].sort(
|
|
44
|
+
getChartSortFn(chart?.sortBy),
|
|
45
|
+
)}
|
|
46
|
+
width={width}
|
|
47
|
+
/>
|
|
42
48
|
</StyledGridPaperSection>
|
|
43
49
|
))}
|
|
44
50
|
</StyledGrid>
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { useMemo } from "react";
|
|
2
2
|
import { SelectCategoryValueView } from "../../../../../../../../../../../common/entities";
|
|
3
|
-
import { sortCategoryValueViewsCount } from "../../../../../../../../../../../common/filters/sort/models/utils";
|
|
4
3
|
import { getPlotOptions } from "../../barX/plot";
|
|
5
4
|
import { getCategoryTotalCount } from "../../barX/utils";
|
|
6
5
|
import { UsePlotOptions } from "./types";
|
|
@@ -10,12 +9,8 @@ export const usePlotOptions = (
|
|
|
10
9
|
width: number,
|
|
11
10
|
barCount: number | undefined,
|
|
12
11
|
): UsePlotOptions => {
|
|
13
|
-
//
|
|
14
|
-
const data = selectCategoryValueViews
|
|
15
|
-
// Sort the category values by count and label.
|
|
16
|
-
.sort(sortCategoryValueViewsCount)
|
|
17
|
-
// Slice the category values to the number of bars to display.
|
|
18
|
-
.slice(0, barCount);
|
|
12
|
+
// Slice the category values to the number of bars to display.
|
|
13
|
+
const data = selectCategoryValueViews.slice(0, barCount);
|
|
19
14
|
|
|
20
15
|
// Build the plot options.
|
|
21
16
|
const options = useMemo(
|
|
@@ -15,12 +15,6 @@ export const CHART_ARGS: ComponentProps<typeof Chart> = {
|
|
|
15
15
|
label: "male",
|
|
16
16
|
selected: false,
|
|
17
17
|
},
|
|
18
|
-
{
|
|
19
|
-
count: 240,
|
|
20
|
-
key: "mixed",
|
|
21
|
-
label: "mixed",
|
|
22
|
-
selected: false,
|
|
23
|
-
},
|
|
24
18
|
{
|
|
25
19
|
count: 78715,
|
|
26
20
|
key: "unknown",
|
|
@@ -33,6 +27,12 @@ export const CHART_ARGS: ComponentProps<typeof Chart> = {
|
|
|
33
27
|
label: "Unspecified",
|
|
34
28
|
selected: false,
|
|
35
29
|
},
|
|
30
|
+
{
|
|
31
|
+
count: 240,
|
|
32
|
+
key: "mixed",
|
|
33
|
+
label: "mixed",
|
|
34
|
+
selected: false,
|
|
35
|
+
},
|
|
36
36
|
],
|
|
37
37
|
width: 800,
|
|
38
38
|
};
|
|
@@ -51,12 +51,6 @@ export const SELECT_CHART_ARGS: ComponentProps<typeof Chart> = {
|
|
|
51
51
|
label: "male",
|
|
52
52
|
selected: true,
|
|
53
53
|
},
|
|
54
|
-
{
|
|
55
|
-
count: 240,
|
|
56
|
-
key: "mixed",
|
|
57
|
-
label: "mixed",
|
|
58
|
-
selected: false,
|
|
59
|
-
},
|
|
60
54
|
{
|
|
61
55
|
count: 78715,
|
|
62
56
|
key: "unknown",
|
|
@@ -69,6 +63,12 @@ export const SELECT_CHART_ARGS: ComponentProps<typeof Chart> = {
|
|
|
69
63
|
label: "Unspecified",
|
|
70
64
|
selected: true,
|
|
71
65
|
},
|
|
66
|
+
{
|
|
67
|
+
count: 240,
|
|
68
|
+
key: "mixed",
|
|
69
|
+
label: "mixed",
|
|
70
|
+
selected: false,
|
|
71
|
+
},
|
|
72
72
|
],
|
|
73
73
|
width: 800,
|
|
74
74
|
};
|
package/src/components/Index/components/EntityView/components/views/ChartView/stories/args.ts
CHANGED
|
@@ -6,7 +6,7 @@ export const CHART_VIEW_ARGS: ComponentProps<typeof ChartView> = {
|
|
|
6
6
|
{
|
|
7
7
|
categoryViews: [
|
|
8
8
|
{
|
|
9
|
-
|
|
9
|
+
chart: { enable: true },
|
|
10
10
|
key: "biological-sex",
|
|
11
11
|
label: "Biological Sex",
|
|
12
12
|
values: [
|
|
@@ -43,7 +43,7 @@ export const CHART_VIEW_ARGS: ComponentProps<typeof ChartView> = {
|
|
|
43
43
|
],
|
|
44
44
|
},
|
|
45
45
|
{
|
|
46
|
-
|
|
46
|
+
chart: { enable: true },
|
|
47
47
|
key: "genusSpecies",
|
|
48
48
|
label: "Genus Species",
|
|
49
49
|
values: [
|
|
@@ -74,7 +74,7 @@ export const CHART_VIEW_ARGS: ComponentProps<typeof ChartView> = {
|
|
|
74
74
|
],
|
|
75
75
|
},
|
|
76
76
|
{
|
|
77
|
-
|
|
77
|
+
chart: { enable: false },
|
|
78
78
|
key: "pairedEnd",
|
|
79
79
|
label: "Paired End",
|
|
80
80
|
values: [
|
|
@@ -13,7 +13,7 @@ export function getSelectCategoryViews(
|
|
|
13
13
|
return categoryFilters
|
|
14
14
|
.flatMap(({ categoryViews }) => categoryViews)
|
|
15
15
|
.filter(isSelectCategoryView)
|
|
16
|
-
.filter(({
|
|
16
|
+
.filter(({ chart }) => chart?.enable !== false)
|
|
17
17
|
.filter(({ values }) => values.length > 0);
|
|
18
18
|
}
|
|
19
19
|
|
|
@@ -83,7 +83,7 @@ function buildCategoryView(
|
|
|
83
83
|
selectCategoryConfig?.mapSelectCategoryValue || getSelectCategoryValue;
|
|
84
84
|
return {
|
|
85
85
|
annotation: selectCategoryConfig?.annotation,
|
|
86
|
-
|
|
86
|
+
chart: selectCategoryConfig?.chart,
|
|
87
87
|
isDisabled: false,
|
|
88
88
|
key: selectCategory.key,
|
|
89
89
|
label: getCategoryLabel(selectCategory.key, selectCategoryConfig),
|
|
@@ -34,17 +34,6 @@ export interface FileFacet {
|
|
|
34
34
|
total: number;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
export enum FILE_MANIFEST_TYPE {
|
|
38
|
-
BULK_DOWNLOAD = "BULK_DOWNLOAD",
|
|
39
|
-
DOWNLOAD_MANIFEST = "DOWNLOAD_MANIFEST",
|
|
40
|
-
ENTITY_BULK_DOWNLOAD = "ENTITY_BULK_DOWNLOAD",
|
|
41
|
-
ENTITY_DOWNLOAD_MANIFEST = "ENTITY_DOWNLOAD_MANIFEST",
|
|
42
|
-
ENTITY_EXPORT_TO_TERRA = "ENTITY_EXPORT_TO_TERRA",
|
|
43
|
-
EXPORT_TO_TERRA = "EXPORT_TO_TERRA",
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
export type FileManifestType = FILE_MANIFEST_TYPE;
|
|
47
|
-
|
|
48
37
|
export type SelectedSearchTermsBySearchKey = Map<
|
|
49
38
|
CategoryKey,
|
|
50
39
|
Set<CategoryValueKey>
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { CHART_SORT_FN } from "../src/common/chart/sort/constants";
|
|
2
|
+
import { CHART_SORT, ChartSortFn } from "../src/common/chart/sort/types";
|
|
3
|
+
import { getChartSortFn } from "../src/common/chart/sort/utils";
|
|
4
|
+
import { SelectCategoryValueView } from "../src/common/entities";
|
|
5
|
+
import {
|
|
6
|
+
sortCategoryValueViewsAlpha,
|
|
7
|
+
sortCategoryValueViewsCount,
|
|
8
|
+
} from "../src/common/filters/sort/models/utils";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Creates a mock category value view for testing.
|
|
12
|
+
* @param key - The key for the category value.
|
|
13
|
+
* @param count - The count for the category value.
|
|
14
|
+
* @returns A mock SelectCategoryValueView.
|
|
15
|
+
*/
|
|
16
|
+
const createMockCategoryValueView = (
|
|
17
|
+
key: unknown,
|
|
18
|
+
count: number,
|
|
19
|
+
): SelectCategoryValueView => ({
|
|
20
|
+
count,
|
|
21
|
+
key,
|
|
22
|
+
label: key ? String(key) : "",
|
|
23
|
+
selected: false,
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
describe("Chart Sort Utils", () => {
|
|
27
|
+
describe("CHART_SORT_FN", () => {
|
|
28
|
+
it("maps CHART_SORT.ALPHA to sortCategoryValueViewsAlpha", () => {
|
|
29
|
+
expect(CHART_SORT_FN[CHART_SORT.ALPHA]).toBe(sortCategoryValueViewsAlpha);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
it("maps CHART_SORT.COUNT to sortCategoryValueViewsCount", () => {
|
|
33
|
+
expect(CHART_SORT_FN[CHART_SORT.COUNT]).toBe(sortCategoryValueViewsCount);
|
|
34
|
+
});
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("getChartSortFn", () => {
|
|
38
|
+
it("returns COUNT sort function when undefined", () => {
|
|
39
|
+
const sortFn = getChartSortFn(undefined);
|
|
40
|
+
expect(sortFn).toBe(sortCategoryValueViewsCount);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it("returns ALPHA sort function for CHART_SORT.ALPHA", () => {
|
|
44
|
+
const sortFn = getChartSortFn(CHART_SORT.ALPHA);
|
|
45
|
+
expect(sortFn).toBe(sortCategoryValueViewsAlpha);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it("returns COUNT sort function for CHART_SORT.COUNT", () => {
|
|
49
|
+
const sortFn = getChartSortFn(CHART_SORT.COUNT);
|
|
50
|
+
expect(sortFn).toBe(sortCategoryValueViewsCount);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("returns custom function when provided", () => {
|
|
54
|
+
const customSortFn: ChartSortFn = (a, b) =>
|
|
55
|
+
a.label.localeCompare(b.label);
|
|
56
|
+
const sortFn = getChartSortFn(customSortFn);
|
|
57
|
+
expect(sortFn).toBe(customSortFn);
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it("custom sort function works correctly", () => {
|
|
61
|
+
// Custom sort: by label length descending
|
|
62
|
+
const customSortFn: ChartSortFn = (a, b) =>
|
|
63
|
+
b.label.length - a.label.length;
|
|
64
|
+
const sortFn = getChartSortFn(customSortFn);
|
|
65
|
+
|
|
66
|
+
const data = [
|
|
67
|
+
createMockCategoryValueView("a", 10),
|
|
68
|
+
createMockCategoryValueView("abc", 5),
|
|
69
|
+
createMockCategoryValueView("ab", 3),
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
const sorted = [...data].sort(sortFn);
|
|
73
|
+
|
|
74
|
+
expect(sorted.map((cv) => cv.label)).toEqual(["abc", "ab", "a"]);
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe("sorting integration", () => {
|
|
79
|
+
const testData = [
|
|
80
|
+
createMockCategoryValueView("Zebra", 5),
|
|
81
|
+
createMockCategoryValueView("Apple", 10),
|
|
82
|
+
createMockCategoryValueView("Banana", 3),
|
|
83
|
+
];
|
|
84
|
+
|
|
85
|
+
it("sorts alphabetically with CHART_SORT.ALPHA", () => {
|
|
86
|
+
const sortFn = getChartSortFn(CHART_SORT.ALPHA);
|
|
87
|
+
const sorted = [...testData].sort(sortFn);
|
|
88
|
+
|
|
89
|
+
expect(sorted.map((cv) => cv.label)).toEqual([
|
|
90
|
+
"Apple",
|
|
91
|
+
"Banana",
|
|
92
|
+
"Zebra",
|
|
93
|
+
]);
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("sorts by count descending with CHART_SORT.COUNT", () => {
|
|
97
|
+
const sortFn = getChartSortFn(CHART_SORT.COUNT);
|
|
98
|
+
const sorted = [...testData].sort(sortFn);
|
|
99
|
+
|
|
100
|
+
expect(sorted.map((cv) => cv.label)).toEqual([
|
|
101
|
+
"Apple",
|
|
102
|
+
"Zebra",
|
|
103
|
+
"Banana",
|
|
104
|
+
]);
|
|
105
|
+
expect(sorted.map((cv) => cv.count)).toEqual([10, 5, 3]);
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
it("defaults to count sort when no option provided", () => {
|
|
109
|
+
const sortFn = getChartSortFn();
|
|
110
|
+
const sorted = [...testData].sort(sortFn);
|
|
111
|
+
|
|
112
|
+
expect(sorted.map((cv) => cv.label)).toEqual([
|
|
113
|
+
"Apple",
|
|
114
|
+
"Zebra",
|
|
115
|
+
"Banana",
|
|
116
|
+
]);
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
});
|