Skip to content

Commit 618022e

Browse files
committed
feat: do not show classification sorting if classification display disabled
Signed-off-by: Dominikus Hellgartner <dominikus.hellgartner@tngtech.com>
1 parent de59d28 commit 618022e

File tree

7 files changed

+124
-62
lines changed

7 files changed

+124
-62
lines changed

src/Frontend/Components/SortButton/SortButton.tsx

+30-56
Original file line numberDiff line numberDiff line change
@@ -2,63 +2,20 @@
22
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
33
//
44
// SPDX-License-Identifier: Apache-2.0
5-
import BarChartIcon from '@mui/icons-material/BarChart';
65
import SortIcon from '@mui/icons-material/Sort';
7-
import SortByAlphaIcon from '@mui/icons-material/SortByAlpha';
8-
import WhatshotIcon from '@mui/icons-material/Whatshot';
96
import MuiBadge from '@mui/material/Badge';
107
import MuiIconButton from '@mui/material/IconButton';
118
import MuiTooltip from '@mui/material/Tooltip';
12-
import { useMemo, useState } from 'react';
9+
import { useCallback, useEffect, useMemo, useState } from 'react';
1310

1411
import { text } from '../../../shared/text';
1512
import { UseFilteredData } from '../../state/variables/use-filtered-data';
16-
import { ClassificationCIcon } from '../Icons/Icons';
1713
import {
1814
SelectMenu,
1915
SelectMenuOption,
2016
SelectMenuProps,
2117
} from '../SelectMenu/SelectMenu';
22-
23-
interface SortOptionConfiguration {
24-
label: string;
25-
icon: React.FC<{ color?: 'action' | 'disabled' }>;
26-
}
27-
28-
export type SortOption =
29-
| 'alphabetically'
30-
| 'criticality'
31-
| 'occurrence'
32-
| 'classification';
33-
34-
type SortConfiguration = Record<SortOption, SortOptionConfiguration>;
35-
36-
export const SORT_CONFIGURATION: SortConfiguration = {
37-
alphabetically: {
38-
label: text.sortings.name,
39-
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
40-
<SortByAlphaIcon color={color || 'action'} fontSize={'inherit'} />
41-
),
42-
},
43-
criticality: {
44-
label: text.sortings.criticality,
45-
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
46-
<WhatshotIcon color={color || 'warning'} fontSize={'inherit'} />
47-
),
48-
},
49-
occurrence: {
50-
label: text.sortings.occurrence,
51-
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
52-
<BarChartIcon color={color || 'info'} fontSize={'inherit'} />
53-
),
54-
},
55-
classification: {
56-
label: text.sortings.classification,
57-
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
58-
<ClassificationCIcon color={color || 'warning'} fontSize={'inherit'} />
59-
),
60-
},
61-
};
18+
import { SortOption, useSortConfiguration } from './useSortingOptions';
6219

6320
interface Props
6421
extends Pick<SelectMenuProps, 'anchorArrow' | 'anchorPosition'> {
@@ -74,30 +31,47 @@ export const SortButton: React.FC<Props> = ({
7431
const [{ sorting, attributions }, setFilteredAttributions] =
7532
useFilteredData();
7633

34+
const sortConfiguration = useSortConfiguration();
35+
36+
const setSorting = useCallback(
37+
(sortOption: SortOption) => {
38+
setFilteredAttributions((prev) => ({
39+
...prev,
40+
sorting: sortOption,
41+
}));
42+
},
43+
[setFilteredAttributions],
44+
);
45+
46+
useEffect(() => {
47+
const availableKeys = Object.entries(sortConfiguration)
48+
.filter(([_, entry]) => entry.active)
49+
.map(([key, _]) => key);
50+
if (!availableKeys.includes(sorting)) {
51+
setSorting('alphabetically');
52+
}
53+
}, [sortConfiguration, sorting, setSorting]);
54+
7755
const sortingOptions = useMemo(
7856
() =>
79-
Object.entries(SORT_CONFIGURATION).map<SelectMenuOption>(
80-
([key, entry]) => {
57+
Object.entries(sortConfiguration)
58+
.filter(([_, entry]) => entry.active)
59+
.map<SelectMenuOption>(([key, entry]) => {
8160
const Icon = entry.icon;
8261
const sortOption: SortOption = key as SortOption;
8362
return {
8463
id: sortOption,
8564
label: entry.label,
8665
selected: sortOption === sorting,
8766
icon: <Icon />,
88-
onAdd: () =>
89-
setFilteredAttributions((prev) => ({
90-
...prev,
91-
sorting: sortOption,
92-
})),
67+
onAdd: () => setSorting(sortOption),
9368
};
94-
},
95-
),
96-
[setFilteredAttributions, sorting],
69+
}),
70+
[sorting, sortConfiguration, setSorting],
9771
);
9872

9973
const disabled = !attributions || !Object.keys(attributions).length;
100-
const BadgeContent = SORT_CONFIGURATION[sorting].icon;
74+
const BadgeContent = sortConfiguration[sorting].icon;
10175

10276
return (
10377
<>

src/Frontend/Components/SortButton/__tests__/SortButton.test.tsx

+23-2
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,16 @@
66
import { screen } from '@testing-library/react';
77
import userEvent from '@testing-library/user-event';
88

9+
import { text } from '../../../../shared/text';
910
import { faker } from '../../../../testing/Faker';
1011
import {
1112
FilteredData,
1213
initialFilteredAttributions,
1314
UseFilteredData,
1415
} from '../../../state/variables/use-filtered-data';
1516
import { renderComponent } from '../../../test-helpers/render';
16-
import { SORT_CONFIGURATION, SortButton, SortOption } from '../SortButton';
17+
import { SortButton } from '../SortButton';
18+
import { SortOption } from '../useSortingOptions';
1719

1820
describe('SortButton', () => {
1921
it('switches to selected sorting', async () => {
@@ -34,7 +36,7 @@ describe('SortButton', () => {
3436

3537
await userEvent.click(screen.getByRole('button', { name: 'sort button' }));
3638
await userEvent.click(
37-
screen.getByRole('menuitem', { name: SORT_CONFIGURATION[sorting].label }),
39+
screen.getByRole('menuitem', { name: text.sortings.criticality }),
3840
);
3941

4042
expect(result!.sorting).toEqual(sorting);
@@ -52,4 +54,23 @@ describe('SortButton', () => {
5254

5355
expect(screen.getByRole('button', { name: 'sort button' })).toBeDisabled();
5456
});
57+
58+
it('shows all sort options', async () => {
59+
const setFilteredData = jest.fn;
60+
const useFilteredData: UseFilteredData = () => [
61+
{
62+
...initialFilteredAttributions,
63+
attributions: faker.opossum.attributions(),
64+
},
65+
setFilteredData,
66+
];
67+
renderComponent(<SortButton useFilteredData={useFilteredData} />);
68+
69+
await userEvent.click(screen.getByRole('button', { name: 'sort button' }));
70+
Object.values(text.sortings).forEach((menuItemText) => {
71+
expect(
72+
screen.getByRole('menuitem', { name: menuItemText }),
73+
).toBeVisible();
74+
});
75+
});
5576
});
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
// SPDX-FileCopyrightText: Meta Platforms, Inc. and its affiliates
2+
// SPDX-FileCopyrightText: TNG Technology Consulting GmbH <https://www.tngtech.com>
3+
//
4+
// SPDX-License-Identifier: Apache-2.0
5+
import BarChartIcon from '@mui/icons-material/BarChart';
6+
import SortByAlphaIcon from '@mui/icons-material/SortByAlpha';
7+
import WhatshotIcon from '@mui/icons-material/Whatshot';
8+
import { useMemo } from 'react';
9+
10+
import { text } from '../../../shared/text';
11+
import { useShowClassifications } from '../../state/variables/use-show-classifications';
12+
import { ClassificationCIcon } from '../Icons/Icons';
13+
14+
export type SortOption =
15+
| 'alphabetically'
16+
| 'criticality'
17+
| 'occurrence'
18+
| 'classification';
19+
20+
export interface SortOptionConfiguration {
21+
label: string;
22+
icon: React.FC<{ color?: 'action' | 'disabled' }>;
23+
active: boolean;
24+
}
25+
26+
export type SortConfiguration = Record<SortOption, SortOptionConfiguration>;
27+
28+
export function useSortConfiguration(): SortConfiguration {
29+
const [showClassifications] = useShowClassifications();
30+
console.log('showClassifications', showClassifications);
31+
32+
return useMemo(() => {
33+
return {
34+
alphabetically: {
35+
label: text.sortings.name,
36+
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
37+
<SortByAlphaIcon color={color || 'action'} fontSize={'inherit'} />
38+
),
39+
active: true,
40+
},
41+
criticality: {
42+
label: text.sortings.criticality,
43+
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
44+
<WhatshotIcon color={color || 'warning'} fontSize={'inherit'} />
45+
),
46+
active: true,
47+
},
48+
occurrence: {
49+
label: text.sortings.occurrence,
50+
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
51+
<BarChartIcon color={color || 'info'} fontSize={'inherit'} />
52+
),
53+
active: true,
54+
},
55+
classification: {
56+
label: text.sortings.classification,
57+
icon: ({ color }: { color?: 'action' | 'disabled' }) => (
58+
<ClassificationCIcon
59+
color={color || 'warning'}
60+
fontSize={'inherit'}
61+
/>
62+
),
63+
active: showClassifications,
64+
},
65+
};
66+
}, [showClassifications]);
67+
}

src/Frontend/state/variables/use-filtered-data.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
//
44
// SPDX-License-Identifier: Apache-2.0
55
import { Attributions } from '../../../shared/shared-types';
6-
import { SortOption } from '../../Components/SortButton/SortButton';
6+
import { SortOption } from '../../Components/SortButton/useSortingOptions';
77
import { Filter, FilterCounts } from '../../shared-constants';
88
import { useAppSelector } from '../hooks';
99
import { getSelectedAttributionId } from '../selectors/resource-selectors';

src/Frontend/util/sort-attributions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import { keyBy, ListIterator, orderBy } from 'lodash';
66

77
import { Attributions, PackageInfo, Relation } from '../../shared/shared-types';
8-
import { SortOption } from '../Components/SortButton/SortButton';
8+
import { SortOption } from '../Components/SortButton/useSortingOptions';
99
import { getCardLabels } from './get-card-labels';
1010

1111
export function sortAttributions({

src/Frontend/web-workers/scripts/get-filtered-attributions.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import {
1111
Relation,
1212
} from '../../../shared/shared-types';
1313
import { text } from '../../../shared/text';
14-
import { SortOption } from '../../Components/SortButton/SortButton';
14+
import { SortOption } from '../../Components/SortButton/useSortingOptions';
1515
import { Filter, FilterCounts, FILTERS } from '../../shared-constants';
1616
import { getClosestParentAttributionIds } from '../../util/get-closest-parent-attributions';
1717
import { getContainedAttributionCount } from '../../util/get-contained-attribution-count';

src/Frontend/web-workers/signals-worker.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
ClassificationsConfig,
99
Resources,
1010
} from '../../shared/shared-types';
11-
import { SortOption } from '../Components/SortButton/SortButton';
11+
import { SortOption } from '../Components/SortButton/useSortingOptions';
1212
import { Filter, FilterCounts, ROOT_PATH } from '../shared-constants';
1313
import { ProgressBarData } from '../types/types';
1414
import {

0 commit comments

Comments
 (0)