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 |
|