Spaces:
Running
Running
feat (Filters): Allow user to select all values in a filter.
Browse files- src/components/filters/Filters.module.scss +10 -0
- src/components/filters/Filters.tsx +60 -4
- src/views/performance-overview/{FilterMetrics.module.scss → Hide.module.scss} +11 -6
- src/views/performance-overview/{FilterMetrics.tsx → Hide.tsx} +68 -42
- src/views/performance-overview/PerformanceOverview.tsx +26 -4
src/components/filters/Filters.module.scss
CHANGED
@@ -75,3 +75,13 @@
|
|
75 |
.filterSelector {
|
76 |
max-width: 25%;
|
77 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
75 |
.filterSelector {
|
76 |
max-width: 25%;
|
77 |
}
|
78 |
+
|
79 |
+
.filterSelector label {
|
80 |
+
width: 100%;
|
81 |
+
}
|
82 |
+
|
83 |
+
.filterLabel {
|
84 |
+
display: flex;
|
85 |
+
justify-content: space-between;
|
86 |
+
align-items: center;
|
87 |
+
}
|
src/components/filters/Filters.tsx
CHANGED
@@ -128,15 +128,43 @@ export default function Filters({
|
|
128 |
{Object.entries(filters).map(([filterType, values]) => {
|
129 |
return (
|
130 |
<div
|
131 |
-
key={
|
|
|
|
|
|
|
|
|
|
|
132 |
className={classes.filterSelector}
|
133 |
>
|
134 |
<FilterableMultiSelect
|
135 |
id={
|
136 |
`${keyPrefix}-filter` + filterType + '-selector'
|
137 |
}
|
138 |
-
titleText={
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
139 |
items={values}
|
|
|
|
|
|
|
|
|
|
|
140 |
itemToString={(item) => String(item)}
|
141 |
onChange={(event) => {
|
142 |
setSelectedFilters((prevState) =>
|
@@ -185,13 +213,41 @@ export default function Filters({
|
|
185 |
{Object.entries(filters).map(([filterType, values]) => {
|
186 |
return (
|
187 |
<div
|
188 |
-
key={
|
|
|
|
|
|
|
|
|
|
|
189 |
className={classes.filterSelector}
|
190 |
>
|
191 |
<FilterableMultiSelect
|
192 |
id={`${keyPrefix}-filter` + filterType + '-selector'}
|
193 |
-
titleText={
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
194 |
items={values}
|
|
|
|
|
|
|
|
|
|
|
195 |
itemToString={(item) => String(item)}
|
196 |
onChange={(event) => {
|
197 |
setSelectedFilters((prevState) =>
|
|
|
128 |
{Object.entries(filters).map(([filterType, values]) => {
|
129 |
return (
|
130 |
<div
|
131 |
+
key={
|
132 |
+
`${keyPrefix}-filter` +
|
133 |
+
filterType +
|
134 |
+
'-selector--' +
|
135 |
+
`${selectedFilters && selectedFilters[filterType] && selectedFilters[filterType] === values}`
|
136 |
+
}
|
137 |
className={classes.filterSelector}
|
138 |
>
|
139 |
<FilterableMultiSelect
|
140 |
id={
|
141 |
`${keyPrefix}-filter` + filterType + '-selector'
|
142 |
}
|
143 |
+
titleText={
|
144 |
+
<div className={classes.filterLabel}>
|
145 |
+
<span>{filterType}</span>
|
146 |
+
<Button
|
147 |
+
kind="ghost"
|
148 |
+
size="sm"
|
149 |
+
onClick={() =>
|
150 |
+
setSelectedFilters((prevState) => {
|
151 |
+
return {
|
152 |
+
...prevState,
|
153 |
+
[filterType]: values,
|
154 |
+
};
|
155 |
+
})
|
156 |
+
}
|
157 |
+
>
|
158 |
+
select all
|
159 |
+
</Button>
|
160 |
+
</div>
|
161 |
+
}
|
162 |
items={values}
|
163 |
+
initialSelectedItems={
|
164 |
+
selectedFilters && selectedFilters[filterType]
|
165 |
+
? selectedFilters[filterType]
|
166 |
+
: []
|
167 |
+
}
|
168 |
itemToString={(item) => String(item)}
|
169 |
onChange={(event) => {
|
170 |
setSelectedFilters((prevState) =>
|
|
|
213 |
{Object.entries(filters).map(([filterType, values]) => {
|
214 |
return (
|
215 |
<div
|
216 |
+
key={
|
217 |
+
`${keyPrefix}-filter` +
|
218 |
+
filterType +
|
219 |
+
'-selector--' +
|
220 |
+
`${selectedFilters && selectedFilters[filterType] && selectedFilters[filterType] === values}`
|
221 |
+
}
|
222 |
className={classes.filterSelector}
|
223 |
>
|
224 |
<FilterableMultiSelect
|
225 |
id={`${keyPrefix}-filter` + filterType + '-selector'}
|
226 |
+
titleText={
|
227 |
+
<div className={classes.filterLabel}>
|
228 |
+
<span>{filterType}</span>
|
229 |
+
<Button
|
230 |
+
kind="ghost"
|
231 |
+
size="sm"
|
232 |
+
onClick={() =>
|
233 |
+
setSelectedFilters((prevState) => {
|
234 |
+
return {
|
235 |
+
...prevState,
|
236 |
+
[filterType]: values,
|
237 |
+
};
|
238 |
+
})
|
239 |
+
}
|
240 |
+
>
|
241 |
+
select all
|
242 |
+
</Button>
|
243 |
+
</div>
|
244 |
+
}
|
245 |
items={values}
|
246 |
+
initialSelectedItems={
|
247 |
+
selectedFilters && selectedFilters[filterType]
|
248 |
+
? selectedFilters[filterType]
|
249 |
+
: []
|
250 |
+
}
|
251 |
itemToString={(item) => String(item)}
|
252 |
onChange={(event) => {
|
253 |
setSelectedFilters((prevState) =>
|
src/views/performance-overview/{FilterMetrics.module.scss → Hide.module.scss}
RENAMED
@@ -19,25 +19,25 @@
|
|
19 |
@use '@carbon/react/scss/spacing' as *;
|
20 |
@use '@carbon/colors' as *;
|
21 |
|
22 |
-
.
|
23 |
align-self: center;
|
24 |
margin-bottom: $spacing-03;
|
25 |
}
|
26 |
|
27 |
-
.
|
28 |
display: flex;
|
29 |
column-gap: $spacing-04;
|
30 |
padding: $spacing-03;
|
31 |
color: inherit !important;
|
32 |
}
|
33 |
|
34 |
-
.
|
35 |
display: flex;
|
36 |
column-gap: $spacing-04;
|
37 |
align-items: center;
|
38 |
}
|
39 |
|
40 |
-
.
|
41 |
display: flex;
|
42 |
column-gap: $spacing-02;
|
43 |
align-items: center;
|
@@ -53,8 +53,9 @@
|
|
53 |
|
54 |
.visible {
|
55 |
display: flex;
|
56 |
-
flex-direction:
|
57 |
-
|
|
|
58 |
animation: fade-in 0.5s;
|
59 |
}
|
60 |
|
@@ -67,3 +68,7 @@
|
|
67 |
opacity: 1;
|
68 |
}
|
69 |
}
|
|
|
|
|
|
|
|
|
|
19 |
@use '@carbon/react/scss/spacing' as *;
|
20 |
@use '@carbon/colors' as *;
|
21 |
|
22 |
+
.hideBtnTooltip {
|
23 |
align-self: center;
|
24 |
margin-bottom: $spacing-03;
|
25 |
}
|
26 |
|
27 |
+
.hideBtn {
|
28 |
display: flex;
|
29 |
column-gap: $spacing-04;
|
30 |
padding: $spacing-03;
|
31 |
color: inherit !important;
|
32 |
}
|
33 |
|
34 |
+
.hideBtnElements {
|
35 |
display: flex;
|
36 |
column-gap: $spacing-04;
|
37 |
align-items: center;
|
38 |
}
|
39 |
|
40 |
+
.hideBtnCaptionElements {
|
41 |
display: flex;
|
42 |
column-gap: $spacing-02;
|
43 |
align-items: center;
|
|
|
53 |
|
54 |
.visible {
|
55 |
display: flex;
|
56 |
+
flex-direction: row;
|
57 |
+
justify-content: center;
|
58 |
+
align-items: flex-start;
|
59 |
animation: fade-in 0.5s;
|
60 |
}
|
61 |
|
|
|
68 |
opacity: 1;
|
69 |
}
|
70 |
}
|
71 |
+
|
72 |
+
.selector {
|
73 |
+
max-width: 30%;
|
74 |
+
}
|
src/views/performance-overview/{FilterMetrics.tsx → Hide.tsx}
RENAMED
@@ -24,83 +24,109 @@ import { useState } from 'react';
|
|
24 |
import { FilterableMultiSelect, Tag, Tooltip, Button } from '@carbon/react';
|
25 |
import { ChevronUp, ChevronDown, SubtractAlt } from '@carbon/icons-react';
|
26 |
|
27 |
-
import { Metric } from '@/src/types';
|
28 |
import { extractMetricDisplayName } from '@/src/utilities/metrics';
|
29 |
|
30 |
-
import classes from './
|
31 |
|
32 |
// ===================================================================================
|
33 |
// TYPES
|
34 |
// ===================================================================================
|
35 |
interface Props {
|
|
|
36 |
metrics: Metric[];
|
|
|
37 |
hiddenMetrics: Metric[];
|
|
|
38 |
setHiddenMetrics: Function;
|
39 |
}
|
40 |
|
41 |
-
export default function
|
|
|
42 |
metrics,
|
|
|
43 |
hiddenMetrics: ignoredMetrics,
|
|
|
44 |
setHiddenMetrics: setIgnoredMetrics,
|
45 |
}: Props) {
|
46 |
// Step 1: Initialize state and necessary variables
|
47 |
-
const [
|
48 |
|
49 |
// Step 2: Render
|
50 |
return (
|
51 |
<>
|
52 |
<Tooltip
|
53 |
-
label={'Click to hide certain metrics'}
|
54 |
align={'right'}
|
55 |
-
className={classes.
|
56 |
>
|
57 |
<Button
|
58 |
-
id={'PerformanceOverview-
|
59 |
-
className={classes.
|
60 |
kind={'ghost'}
|
61 |
size={'sm'}
|
62 |
onClick={() => {
|
63 |
-
|
64 |
}}
|
65 |
>
|
66 |
-
<div className={classes.
|
67 |
-
{
|
68 |
-
|
69 |
-
|
70 |
-
<ChevronDown size={24} />
|
71 |
-
)}
|
72 |
-
<div className={classes.filterMetricsBtnCaptionElements}>
|
73 |
-
<h5>Hide Metrics</h5>
|
74 |
<SubtractAlt />
|
75 |
</div>
|
76 |
</div>
|
77 |
</Button>
|
78 |
</Tooltip>
|
79 |
-
{
|
80 |
-
<div
|
81 |
-
className={
|
82 |
-
|
83 |
-
|
84 |
-
|
85 |
-
|
86 |
-
|
87 |
-
|
88 |
-
|
89 |
-
|
90 |
-
|
91 |
-
|
92 |
-
|
93 |
-
|
94 |
-
|
95 |
-
|
96 |
-
|
97 |
-
|
98 |
-
|
99 |
-
|
100 |
-
|
101 |
-
|
102 |
-
|
103 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
104 |
</div>
|
105 |
</div>
|
106 |
) : null}
|
|
|
24 |
import { FilterableMultiSelect, Tag, Tooltip, Button } from '@carbon/react';
|
25 |
import { ChevronUp, ChevronDown, SubtractAlt } from '@carbon/icons-react';
|
26 |
|
27 |
+
import { Metric, Model } from '@/src/types';
|
28 |
import { extractMetricDisplayName } from '@/src/utilities/metrics';
|
29 |
|
30 |
+
import classes from './Hide.module.scss';
|
31 |
|
32 |
// ===================================================================================
|
33 |
// TYPES
|
34 |
// ===================================================================================
|
35 |
interface Props {
|
36 |
+
models: Model[];
|
37 |
metrics: Metric[];
|
38 |
+
hiddenModels: Model[];
|
39 |
hiddenMetrics: Metric[];
|
40 |
+
setHiddenModels: Function;
|
41 |
setHiddenMetrics: Function;
|
42 |
}
|
43 |
|
44 |
+
export default function HidePanel({
|
45 |
+
models,
|
46 |
metrics,
|
47 |
+
hiddenModels: ignoredModels,
|
48 |
hiddenMetrics: ignoredMetrics,
|
49 |
+
setHiddenModels: setIgnoredModels,
|
50 |
setHiddenMetrics: setIgnoredMetrics,
|
51 |
}: Props) {
|
52 |
// Step 1: Initialize state and necessary variables
|
53 |
+
const [show, setShow] = useState<boolean>(true);
|
54 |
|
55 |
// Step 2: Render
|
56 |
return (
|
57 |
<>
|
58 |
<Tooltip
|
59 |
+
label={'Click to hide certain models & metrics'}
|
60 |
align={'right'}
|
61 |
+
className={classes.hideBtnTooltip}
|
62 |
>
|
63 |
<Button
|
64 |
+
id={'PerformanceOverview-hide--Ignore'}
|
65 |
+
className={classes.hideBtn}
|
66 |
kind={'ghost'}
|
67 |
size={'sm'}
|
68 |
onClick={() => {
|
69 |
+
setShow(!show);
|
70 |
}}
|
71 |
>
|
72 |
+
<div className={classes.hideBtnElements}>
|
73 |
+
{show ? <ChevronUp size={24} /> : <ChevronDown size={24} />}
|
74 |
+
<div className={classes.hideBtnCaptionElements}>
|
75 |
+
<h5>Hide Models & Metrics</h5>
|
|
|
|
|
|
|
|
|
76 |
<SubtractAlt />
|
77 |
</div>
|
78 |
</div>
|
79 |
</Button>
|
80 |
</Tooltip>
|
81 |
+
{show ? (
|
82 |
+
<div className={cx(classes.container, show && classes.visible)}>
|
83 |
+
<div className={classes.selector}>
|
84 |
+
<FilterableMultiSelect
|
85 |
+
id={'model--limiter'}
|
86 |
+
titleText="Models"
|
87 |
+
items={models}
|
88 |
+
itemToString={(item) => (item.name ? item.name : item.modelId)}
|
89 |
+
onChange={(event) => {
|
90 |
+
setIgnoredModels(event.selectedItems);
|
91 |
+
}}
|
92 |
+
></FilterableMultiSelect>
|
93 |
+
<div>
|
94 |
+
{ignoredModels.map((model) => {
|
95 |
+
return (
|
96 |
+
<Tag
|
97 |
+
type={'cool-gray'}
|
98 |
+
key={`filtered-model--` + model.modelId}
|
99 |
+
>
|
100 |
+
{model.name ? model.name : model.modelId}
|
101 |
+
</Tag>
|
102 |
+
);
|
103 |
+
})}
|
104 |
+
</div>
|
105 |
+
</div>
|
106 |
+
<div className={classes.selector}>
|
107 |
+
<FilterableMultiSelect
|
108 |
+
id={'metrics--limiter'}
|
109 |
+
titleText="Metrics"
|
110 |
+
items={metrics}
|
111 |
+
itemToString={(item) =>
|
112 |
+
item.displayName ? item.displayName : item.name
|
113 |
+
}
|
114 |
+
onChange={(event) => {
|
115 |
+
setIgnoredMetrics(event.selectedItems);
|
116 |
+
}}
|
117 |
+
></FilterableMultiSelect>
|
118 |
+
<div>
|
119 |
+
{ignoredMetrics.map((metric) => {
|
120 |
+
return (
|
121 |
+
<Tag
|
122 |
+
type={'cool-gray'}
|
123 |
+
key={`filtered-metric--` + metric.name}
|
124 |
+
>
|
125 |
+
{extractMetricDisplayName(metric)}
|
126 |
+
</Tag>
|
127 |
+
);
|
128 |
+
})}
|
129 |
+
</div>
|
130 |
</div>
|
131 |
</div>
|
132 |
) : null}
|
src/views/performance-overview/PerformanceOverview.tsx
CHANGED
@@ -61,7 +61,7 @@ import { areObjectsIntersecting } from '@/src/utilities/objects';
|
|
61 |
import { getModelColorPalette } from '@/src/utilities/colors';
|
62 |
import AggregatorSelector from '@/src/components/selectors/AggregatorSelector';
|
63 |
import Filters from '@/src/components/filters/Filters';
|
64 |
-
import
|
65 |
|
66 |
import '@carbon/charts-react/styles.css';
|
67 |
import classes from './PerformanceOverview.module.scss';
|
@@ -398,6 +398,7 @@ export default function PerformanceOverview({
|
|
398 |
[key: string]: string[];
|
399 |
}>({});
|
400 |
const [modelColors, modelOrder] = getModelColorPalette(models);
|
|
|
401 |
const [hiddenMetrics, setHiddenMetrics] = useState<Metric[]>([]);
|
402 |
|
403 |
// Step 2: Run effects
|
@@ -656,13 +657,30 @@ export default function PerformanceOverview({
|
|
656 |
);
|
657 |
}
|
658 |
|
659 |
-
// Step 4:
|
|
|
|
|
|
|
660 |
// Step 4.a: Human metrics
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
661 |
if (Array.isArray(hData)) {
|
662 |
calculateRanks(hData);
|
663 |
}
|
664 |
|
665 |
-
// Step
|
666 |
if (Array.isArray(aData)) {
|
667 |
calculateRanks(aData);
|
668 |
}
|
@@ -674,6 +692,7 @@ export default function PerformanceOverview({
|
|
674 |
models,
|
675 |
selectedAggregators,
|
676 |
selectedFilters,
|
|
|
677 |
hiddenMetrics,
|
678 |
]);
|
679 |
|
@@ -731,9 +750,12 @@ export default function PerformanceOverview({
|
|
731 |
/>
|
732 |
) : null}
|
733 |
|
734 |
-
<
|
|
|
735 |
metrics={metrics}
|
|
|
736 |
hiddenMetrics={hiddenMetrics}
|
|
|
737 |
setHiddenMetrics={setHiddenMetrics}
|
738 |
/>
|
739 |
|
|
|
61 |
import { getModelColorPalette } from '@/src/utilities/colors';
|
62 |
import AggregatorSelector from '@/src/components/selectors/AggregatorSelector';
|
63 |
import Filters from '@/src/components/filters/Filters';
|
64 |
+
import HidePanel from '@/src/views/performance-overview/Hide';
|
65 |
|
66 |
import '@carbon/charts-react/styles.css';
|
67 |
import classes from './PerformanceOverview.module.scss';
|
|
|
398 |
[key: string]: string[];
|
399 |
}>({});
|
400 |
const [modelColors, modelOrder] = getModelColorPalette(models);
|
401 |
+
const [hiddenModels, setHiddenModels] = useState<Model[]>([]);
|
402 |
const [hiddenMetrics, setHiddenMetrics] = useState<Metric[]>([]);
|
403 |
|
404 |
// Step 2: Run effects
|
|
|
657 |
);
|
658 |
}
|
659 |
|
660 |
+
// Step 4: Filter hidden models data
|
661 |
+
const hiddenModelNames = hiddenModels.map((model) =>
|
662 |
+
model.name ? model.name : model.modelId,
|
663 |
+
);
|
664 |
// Step 4.a: Human metrics
|
665 |
+
if (Array.isArray(hData)) {
|
666 |
+
hData = hData.filter(
|
667 |
+
(entry) => !hiddenModelNames.includes(entry.model),
|
668 |
+
);
|
669 |
+
}
|
670 |
+
// Step 4.b: Algorithmic metrics
|
671 |
+
if (Array.isArray(aData)) {
|
672 |
+
aData = aData.filter(
|
673 |
+
(entry) => !hiddenModelNames.includes(entry.model),
|
674 |
+
);
|
675 |
+
}
|
676 |
+
|
677 |
+
// Step 5: Generate add rank information
|
678 |
+
// Step 5.a: Human metrics
|
679 |
if (Array.isArray(hData)) {
|
680 |
calculateRanks(hData);
|
681 |
}
|
682 |
|
683 |
+
// Step 5.b: Algorithmic metrics
|
684 |
if (Array.isArray(aData)) {
|
685 |
calculateRanks(aData);
|
686 |
}
|
|
|
692 |
models,
|
693 |
selectedAggregators,
|
694 |
selectedFilters,
|
695 |
+
hiddenModels,
|
696 |
hiddenMetrics,
|
697 |
]);
|
698 |
|
|
|
750 |
/>
|
751 |
) : null}
|
752 |
|
753 |
+
<HidePanel
|
754 |
+
models={models}
|
755 |
metrics={metrics}
|
756 |
+
hiddenModels={hiddenModels}
|
757 |
hiddenMetrics={hiddenMetrics}
|
758 |
+
setHiddenModels={setHiddenModels}
|
759 |
setHiddenMetrics={setHiddenMetrics}
|
760 |
/>
|
761 |
|