aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/design-system/src/components/icons/QualifierIcon.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx10
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx55
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.tsx68
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx69
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx44
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx31
-rw-r--r--server/sonar-web/src/main/js/apps/component-measures/style.css16
-rw-r--r--sonar-core/src/main/resources/org/sonar/l10n/core.properties1
9 files changed, 158 insertions, 180 deletions
diff --git a/server/sonar-web/design-system/src/components/icons/QualifierIcon.tsx b/server/sonar-web/design-system/src/components/icons/QualifierIcon.tsx
index 4f5bbc4d99b..92685c586f9 100644
--- a/server/sonar-web/design-system/src/components/icons/QualifierIcon.tsx
+++ b/server/sonar-web/design-system/src/components/icons/QualifierIcon.tsx
@@ -21,7 +21,7 @@ import { useTheme } from '@emotion/react';
import { themeColor } from '../../helpers/theme';
import { DirectoryIcon } from './DirectoryIcon';
import { FileIcon } from './FileIcon';
-import { IconProps } from './Icon';
+import { CustomIcon, IconProps } from './Icon';
import { ProjectIcon } from './ProjectIcon';
import { TestFileIcon } from './TestFileIcon';
@@ -41,7 +41,49 @@ export function QualifierIcon({ qualifier, fill, ...iconProps }: Props) {
fil: <FileIcon fill={fill ?? themeColor('iconFile')({ theme })} {...iconProps} />,
trk: <ProjectIcon fill={fill ?? themeColor('iconProject')({ theme })} {...iconProps} />,
uts: <TestFileIcon fill={fill ?? themeColor('iconProject')({ theme })} {...iconProps} />,
+ app: ApplicationIcon({ fill: fill ?? themeColor('iconProject')({ theme }), ...iconProps }),
+ vw: PortfolioIcon({ fill: fill ?? themeColor('iconProject')({ theme }), ...iconProps }),
+ svw: SubPortfolioIcon({ fill: fill ?? themeColor('iconProject')({ theme }), ...iconProps }),
}[qualifier.toLowerCase()];
return icon ?? null;
}
+
+function PortfolioIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
+ const theme = useTheme();
+
+ return (
+ <CustomIcon {...iconProps}>
+ <path
+ d="M14.97 14.97H1.016V1.015H14.97V14.97zm-1-12.955H2.015V13.97H13.97V2.015zm-.973 10.982H9V9h3.997v3.997zM7 12.996H3.004V9H7v3.996zM11.997 10H10v1.997h1.997V10zM6 10H4.004v1.996H6V10zm1-3H3.006V3.006H7V7zm5.985 0H9V3.015h3.985V7zM6 4.006H4.006V6H6V4.006zm5.985.009H10V6h1.985V4.015z"
+ fill={themeColor(fill)({ theme })}
+ />
+ </CustomIcon>
+ );
+}
+
+function ApplicationIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
+ const theme = useTheme();
+
+ return (
+ <CustomIcon {...iconProps}>
+ <path
+ d="M3.014 10.986a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zm9.984 0a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zm-5.004-.021c1.103 0 2 .896 2 2s-.897 2-2 2a2 2 0 0 1 0-4zm-4.98 1.021a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm-5.004-.021a1 1 0 1 1 0 2 1 1 0 0 1 0-2zM2.984 6a2 2 0 1 1-.001 4.001A2 2 0 0 1 2.984 6zm9.984 0a2 2 0 1 1-.001 4.001A2 2 0 0 1 12.968 6zm-5.004-.021c1.103 0 2 .897 2 2a2 2 0 1 1-2-2zM2.984 7a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm-5.004-.021a1.001 1.001 0 0 1 0 2 1 1 0 0 1 0-2zM3 1.025a2 2 0 1 1-.001 4.001A2 2 0 0 1 3 1.025zm9.984 0a2 2 0 1 1-.001 4.001 2 2 0 0 1 .001-4.001zM7.98 1.004c1.103 0 2 .896 2 2s-.897 2-2 2a2 2 0 0 1 0-4zM3 2.025a1 1 0 1 1 0 2 1 1 0 0 1 0-2zm9.984 0a1 1 0 1 1 0 2 1 1 0 0 1 0-2zM7.98 2.004a1.001 1.001 0 0 1 0 2 1 1 0 0 1 0-2z"
+ fill={themeColor(fill)({ theme })}
+ />
+ </CustomIcon>
+ );
+}
+
+function SubPortfolioIcon({ fill = 'currentColor', ...iconProps }: IconProps) {
+ const theme = useTheme();
+
+ return (
+ <CustomIcon {...iconProps}>
+ <path
+ d="M14 7h2v9H7v-2H0V0h14v7zM8 8v7h7V8H8zm3 6H9v-2h2v2zm3 0h-2v-2h2v2zm-1-7V1H1v12h6V7h6zm-7 5H2V8h4v4zm5-1H9V9h2v2zm3 0h-2V9h2v2zM5 9H3v2h2V9zm1-3H2V2h4v4zm6 0H8V2h4v4zM5 3H3v2h2V3zm6 0H9v2h2V3z"
+ fill={themeColor(fill)({ theme })}
+ />
+ </CustomIcon>
+ );
+}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
index be3ab4737bb..6d8679e4a7b 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/__tests__/ComponentMeasures-it.tsx
@@ -255,7 +255,7 @@ describe('navigation', () => {
within(ui.measuresRow('test1.js').get()).getByRole('cell', { name: '2' })
).toBeInTheDocument();
- await user.click(ui.fileLink('foo:folderA').get());
+ await user.click(ui.fileLink('folderA').get());
expect(
within(ui.measuresRow('out.tsx').get()).getByRole('cell', { name: '1' })
).toBeInTheDocument();
@@ -263,7 +263,7 @@ describe('navigation', () => {
within(ui.measuresRow('in.tsx').get()).getByRole('cell', { name: '2' })
).toBeInTheDocument();
- await user.click(ui.fileLink('foo:folderA/out.tsx').get());
+ await user.click(ui.fileLink('out.tsx').get());
expect((await ui.sourceCode.findAll()).length).toBeGreaterThan(0);
// Go back using the breadcrumbs.
@@ -288,7 +288,7 @@ describe('navigation', () => {
within(ui.measuresRow('test1.js').get()).getByRole('cell', { name: '2' })
).toBeInTheDocument();
- await user.click(ui.fileLink('foo:folderA/out.tsx').get());
+ await user.click(ui.fileLink('out.tsx').get());
expect((await ui.sourceCode.findAll()).length).toBeGreaterThan(0);
});
@@ -479,7 +479,9 @@ function getPageObject() {
detailsUnavailableText: byText('component_measures.details_are_not_available'),
noAccessWarning: byRole('alert'),
showingOutOfTxt: (x: string, y: string) => byText(`x_of_y_shown.${x}.${y}`),
- showAllBtn: byRole('button', { name: 'show_them' }),
+ showAllBtn: byRole('button', {
+ name: 'component_measures.hidden_best_score_metrics_show_label',
+ }),
goToActivityLink: byRole('link', { name: 'component_measures.show_metric_history' }),
};
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx
index 3f43f541f46..4a2c158e82c 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentCell.tsx
@@ -17,23 +17,14 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ContentCell, HoverLink, Note, QualifierIcon } from 'design-system';
import * as React from 'react';
import { To } from 'react-router-dom';
-import Link from '../../../components/common/Link';
-import BranchIcon from '../../../components/icons/BranchIcon';
-import LinkIcon from '../../../components/icons/LinkIcon';
-import QualifierIcon from '../../../components/icons/QualifierIcon';
import { fillBranchLike } from '../../../helpers/branch-like';
-import { translate } from '../../../helpers/l10n';
import { splitPath } from '../../../helpers/path';
import { getComponentDrilldownUrlWithSelection, getProjectUrl } from '../../../helpers/urls';
import { BranchLike } from '../../../types/branch-like';
-import {
- ComponentQualifier,
- isApplication,
- isPortfolioLike,
- isProject,
-} from '../../../types/component';
+import { ComponentQualifier, isApplication, isProject } from '../../../types/component';
import { MeasurePageView } from '../../../types/measures';
import { MetricKey } from '../../../types/metrics';
import { ComponentMeasure, ComponentMeasureEnhanced, Metric } from '../../../types/types';
@@ -93,34 +84,18 @@ export default function ComponentCell(props: ComponentCellProps) {
}
return (
- <td className="measure-details-component-cell">
- <div className="text-ellipsis">
- <Link
- className="link-no-underline"
- to={path}
- id={'component-measures-component-link-' + component.key}
- >
- {component.refKey && (
- <span className="big-spacer-right">
- <LinkIcon />
- </span>
- )}
- <span title={component.key}>
- <QualifierIcon className="little-spacer-right" qualifier={component.qualifier} />
- {head.length > 0 && <span className="note">{head}/</span>}
- <span>{tail}</span>
- {(isApplication(rootComponent.qualifier) || isPortfolioLike(rootComponent.qualifier)) &&
- (component.branch ? (
- <>
- <BranchIcon className="spacer-left little-spacer-right" />
- <span className="note">{component.branch}</span>
- </>
- ) : (
- <span className="spacer-left badge">{translate('branches.main_branch')}</span>
- ))}
- </span>
- </Link>
- </div>
- </td>
+ <ContentCell className="sw-py-3 sw-truncate sw-flex">
+ <HoverLink
+ aria-hidden={true}
+ tabIndex={-1}
+ icon={<QualifierIcon qualifier={component.qualifier} />}
+ to={path}
+ title={component.path}
+ />
+ <HoverLink to={path} title={component.path}>
+ {head.length > 0 && <Note>{head}/</Note>}
+ <strong>{tail}</strong>
+ </HoverLink>
+ </ContentCell>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.tsx
index dd7f9ae2593..d67a32ddf3d 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsList.tsx
@@ -17,15 +17,16 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ContentCell, NumericalCell, Table, TableRow, TableRowInteractive } from 'design-system';
import * as React from 'react';
-import { getComponentMeasureUniqueKey } from '../../../helpers/component';
import { getLocalizedMetricName } from '../../../helpers/l10n';
import { BranchLike } from '../../../types/branch-like';
import { MeasurePageView } from '../../../types/measures';
import { ComponentMeasure, ComponentMeasureEnhanced, Dict, Metric } from '../../../types/types';
import { complementary } from '../config/complementary';
-import ComponentsListRow from './ComponentsListRow';
+import ComponentCell from './ComponentCell';
import EmptyResult from './EmptyResult';
+import MeasureCell from './MeasureCell';
interface Props {
branchLike?: BranchLike;
@@ -38,44 +39,51 @@ interface Props {
}
export default function ComponentsList({ components, metric, metrics, ...props }: Props) {
+ const { branchLike, rootComponent, selectedComponent } = props;
+
if (!components.length) {
return <EmptyResult />;
}
const otherMetrics = (complementary[metric.key] || []).map((key) => metrics[key]);
return (
- <table className="data zebra zebra-hover">
- {otherMetrics.length > 0 && (
- <thead>
- <tr>
- <th>&nbsp;</th>
- <th className="text-right">
- <span className="small">{getLocalizedMetricName(metric)}</span>
- </th>
+ <Table
+ gridTemplate={`1fr repeat(${otherMetrics.length + 1}, min-content)`}
+ header={
+ otherMetrics.length > 0 && (
+ <TableRow>
+ <ContentCell />
+ <NumericalCell className="sw-body-sm">{getLocalizedMetricName(metric)}</NumericalCell>
{otherMetrics.map((metric) => (
- <th className="text-right" key={metric.key}>
- <span className="small">{getLocalizedMetricName(metric)}</span>
- </th>
+ <NumericalCell className="sw-body-sm" key={metric.key}>
+ {getLocalizedMetricName(metric)}
+ </NumericalCell>
))}
- </tr>
- </thead>
- )}
-
- <tbody>
- {components.map((component) => (
- <ComponentsListRow
+ </TableRow>
+ )
+ }
+ >
+ {components.map((component) => (
+ <TableRowInteractive
+ key={component.key}
+ className="it__measures-component-row"
+ selected={component.key === selectedComponent?.key}
+ >
+ <ComponentCell
+ branchLike={branchLike}
component={component}
- isSelected={
- getComponentMeasureUniqueKey(component) ===
- getComponentMeasureUniqueKey(props.selectedComponent)
- }
- key={getComponentMeasureUniqueKey(component)}
metric={metric}
- otherMetrics={otherMetrics}
- {...props}
+ rootComponent={rootComponent}
+ view={props.view}
/>
- ))}
- </tbody>
- </table>
+
+ <MeasureCell component={component} metric={metric} />
+
+ {otherMetrics.map((metric) => (
+ <MeasureCell key={metric.key} component={component} metric={metric} />
+ ))}
+ </TableRowInteractive>
+ ))}
+ </Table>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx
deleted file mode 100644
index fb761dafb36..00000000000
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/ComponentsListRow.tsx
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2023 SonarSource SA
- * mailto:info AT sonarsource DOT com
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-import classNames from 'classnames';
-import * as React from 'react';
-import { BranchLike } from '../../../types/branch-like';
-import { MeasurePageView } from '../../../types/measures';
-import { ComponentMeasure, ComponentMeasureEnhanced, Metric } from '../../../types/types';
-import ComponentCell from './ComponentCell';
-import MeasureCell from './MeasureCell';
-
-interface Props {
- branchLike?: BranchLike;
- component: ComponentMeasureEnhanced;
- isSelected: boolean;
- otherMetrics: Metric[];
- metric: Metric;
- rootComponent: ComponentMeasure;
- view: MeasurePageView;
-}
-
-export default function ComponentsListRow(props: Props) {
- const { branchLike, component, rootComponent } = props;
- const otherMeasures = props.otherMetrics.map((metric) => {
- const measure = component.measures.find((measure) => measure.metric.key === metric.key);
- return { ...measure, metric };
- });
- const rowClass = classNames('measure-details-component-row', {
- selected: props.isSelected,
- });
- return (
- <tr className={rowClass}>
- <ComponentCell
- branchLike={branchLike}
- component={component}
- metric={props.metric}
- rootComponent={rootComponent}
- view={props.view}
- />
-
- <MeasureCell component={component} metric={props.metric} />
-
- {otherMeasures.map((measure) => (
- <MeasureCell
- component={component}
- key={measure.metric.key}
- measure={measure}
- metric={measure.metric}
- />
- ))}
- </tr>
- );
-}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx
index a909faf1575..5c98cb047f4 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/FilesView.tsx
@@ -17,17 +17,17 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { ButtonSecondary, FlagMessage } from 'design-system';
import { throttle } from 'lodash';
import * as React from 'react';
import ListFooter from '../../../components/controls/ListFooter';
-import { Button } from '../../../components/controls/buttons';
-import { Alert } from '../../../components/ui/Alert';
import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
import { KeyboardKeys } from '../../../helpers/keycodes';
import { translate, translateWithParameters } from '../../../helpers/l10n';
import { formatMeasure, isDiffMetric, isPeriodBestValue } from '../../../helpers/measures';
import { BranchLike } from '../../../types/branch-like';
import { MeasurePageView } from '../../../types/measures';
+import { MetricType } from '../../../types/metrics';
import {
ComponentMeasure,
ComponentMeasureEnhanced,
@@ -181,18 +181,34 @@ export default class FilesView extends React.PureComponent<Props, State> {
view={this.props.view}
/>
{hidingBestMeasures && this.props.paging && (
- <Alert className="spacer-top" variant="info">
- <div className="display-flex-center">
- {translateWithParameters(
- 'component_measures.hidden_best_score_metrics',
- formatMeasure(this.props.paging.total - filteredComponents.length, 'INT'),
- formatMeasure(this.props.metric.bestValue, this.props.metric.type)
- )}
- <Button className="button-small spacer-left" onClick={this.handleShowBestMeasures}>
- {translate('show_them')}
- </Button>
- </div>
- </Alert>
+ <FlagMessage
+ ariaLabel={translateWithParameters(
+ 'component_measures.hidden_best_score_metrics',
+ formatMeasure(
+ this.props.paging.total - filteredComponents.length,
+ MetricType.Integer
+ ),
+ formatMeasure(this.props.metric.bestValue, this.props.metric.type)
+ )}
+ variant="info"
+ className="sw-mt-4"
+ >
+ {translateWithParameters(
+ 'component_measures.hidden_best_score_metrics',
+ formatMeasure(
+ this.props.paging.total - filteredComponents.length,
+ MetricType.Integer
+ ),
+ formatMeasure(this.props.metric.bestValue, this.props.metric.type)
+ )}
+ <ButtonSecondary
+ onClick={this.handleShowBestMeasures}
+ className="sw-ml-4"
+ aria-label={translate('component_measures.hidden_best_score_metrics_show_label')}
+ >
+ {translate('show_them')}
+ </ButtonSecondary>
+ </FlagMessage>
)}
{!hidingBestMeasures && this.props.paging && this.props.components.length > 0 && (
<ListFooter
diff --git a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx
index 28699421570..fe2ad2a372b 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx
+++ b/server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx
@@ -17,9 +17,12 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { MetricsLabel, MetricsRatingBadge, NumericalCell } from 'design-system';
import * as React from 'react';
import Measure from '../../../components/measure/Measure';
-import { isDiffMetric } from '../../../helpers/measures';
+import { translate, translateWithParameters } from '../../../helpers/l10n';
+import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
+import { MetricType } from '../../../types/metrics';
import { ComponentMeasureEnhanced, MeasureEnhanced, Metric } from '../../../types/types';
interface Props {
@@ -35,10 +38,26 @@ export default function MeasureCell({ component, measure, metric }: Props) {
const value = getValue(measure || component);
return (
- <td className="thin nowrap text-right">
- <span id={`component-measures-component-measure-${component.key}-${metric.key}`}>
- <Measure metricKey={metric.key} metricType={metric.type} value={value} small={true} />
- </span>
- </td>
+ <NumericalCell className="sw-py-3">
+ <Measure
+ metricKey={metric.key}
+ metricType={metric.type}
+ value={value}
+ small={true}
+ ratingComponent={
+ <MetricsRatingBadge
+ label={
+ value
+ ? translateWithParameters(
+ 'metric.has_rating_X',
+ formatMeasure(value, MetricType.Rating)
+ )
+ : translate('metric.no_rating')
+ }
+ rating={formatMeasure(value, MetricType.Rating) as MetricsLabel}
+ />
+ }
+ />
+ </NumericalCell>
);
}
diff --git a/server/sonar-web/src/main/js/apps/component-measures/style.css b/server/sonar-web/src/main/js/apps/component-measures/style.css
index e4d8107cab4..218abc31966 100644
--- a/server/sonar-web/src/main/js/apps/component-measures/style.css
+++ b/server/sonar-web/src/main/js/apps/component-measures/style.css
@@ -78,18 +78,6 @@ button.search-navigator-facet {
margin-top: 4px;
}
-.measure-details-component-row.selected {
- background-color: var(--lightBlue) !important;
-}
-
-.measure-details-component-cell {
- max-width: 0;
-}
-
-.measure-details-component-cell > div {
- max-width: 100%;
-}
-
.domain-measures-value .rating,
.measure-details-value .rating {
width: 18px;
@@ -122,7 +110,3 @@ button.search-navigator-facet {
width: calc(60vw - 80px);
}
}
-
-.measure-favorite svg {
- vertical-align: middle;
-}
diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
index 2af9659f827..f1c615589cd 100644
--- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties
+++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties
@@ -3656,6 +3656,7 @@ component_measures.to_select_files=to select files
component_measures.to_navigate=to navigate
component_measures.to_navigate_files=to next/previous file
component_measures.hidden_best_score_metrics=There are {0} hidden components with a score of {1}.
+component_measures.hidden_best_score_metrics_show_label=Show hidden components
component_measures.navigation=Measures navigation
component_measures.skip_to_navigation=Skip to measure navigation