]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22168 Align measure component
authorIsmail Cherri <ismail.cherri@sonarsource.com>
Mon, 6 May 2024 09:07:57 +0000 (11:07 +0200)
committersonartech <sonartech@sonarsource.com>
Tue, 7 May 2024 20:02:48 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/code/components/ComponentMeasure.tsx
server/sonar-web/src/main/js/apps/component-measures/components/MeasureHeader.tsx
server/sonar-web/src/main/js/apps/component-measures/drilldown/MeasureCell.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/SubnavigationMeasureValue.tsx
server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCard.tsx
server/sonar-web/src/main/js/apps/projects/components/project-card/ProjectCardMeasures.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSidebarHeader.tsx
server/sonar-web/src/main/js/components/measure/Measure.tsx [deleted file]
server/sonar-web/src/main/js/components/measure/MeasureIndicator.tsx
server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx [new file with mode: 0644]

index 800af9d358f53c69a709637a20b01761a77e33d2..d9d9b3251f37f0cee4ff6a1166824fa733bb668b 100644 (file)
@@ -26,10 +26,10 @@ import {
   RatingEnum,
 } from 'design-system';
 import * as React from 'react';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { formatMeasure } from '~sonar-aligned/helpers/measures';
 import { Status } from '~sonar-aligned/types/common';
 import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import Measure from '../../../components/measure/Measure';
 import { getLeakValue } from '../../../components/measure/utils';
 import {
   CCT_SOFTWARE_QUALITY_METRICS,
index c0ee151f811c9b2f968076bac529cadf914d812b..aaed001569ca2330c95de0488545ae1c368497d4 100644 (file)
  */
 import { LinkStandalone } from '@sonarsource/echoes-react';
 import classNames from 'classnames';
-import { MetricsRatingBadge, RatingLabel } from 'design-system';
 import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
+import { MetricKey } from '~sonar-aligned/types/metrics';
 import LanguageDistribution from '../../../components/charts/LanguageDistribution';
 import Tooltip from '../../../components/controls/Tooltip';
-import Measure from '../../../components/measure/Measure';
-import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
+import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
 import { isDiffMetric } from '../../../helpers/measures';
 import { getMeasureHistoryUrl } from '../../../helpers/urls';
 import { BranchLike } from '../../../types/branch-like';
@@ -69,19 +67,7 @@ export default function MeasureHeader(props: Readonly<Props>) {
               metricKey={metric.key}
               metricType={metric.type}
               value={measureValue}
-              ratingComponent={
-                <MetricsRatingBadge
-                  label={
-                    measureValue
-                      ? translateWithParameters(
-                          'metric.has_rating_X',
-                          formatMeasure(measureValue, MetricType.Rating),
-                        )
-                      : translate('metric.no_rating')
-                  }
-                  rating={formatMeasure(measureValue, MetricType.Rating) as RatingLabel}
-                />
-              }
+              badgeSize="sm"
             />
           </div>
 
index 11518a5c49018e0a0676cae44da6c397c03398c8..2768f777df9374348e256a71d5a24fe87bbdcd34 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { MetricsRatingBadge, NumericalCell, RatingLabel } from 'design-system';
+import { NumericalCell } from 'design-system';
 import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import Measure from '../../../components/measure/Measure';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { getCCTMeasureValue, isDiffMetric } from '../../../helpers/measures';
 import { ComponentMeasureEnhanced, MeasureEnhanced, Metric } from '../../../types/types';
 
@@ -32,7 +29,7 @@ interface Props {
   metric: Metric;
 }
 
-export default function MeasureCell({ component, measure, metric }: Props) {
+export default function MeasureCell({ component, measure, metric }: Readonly<Props>) {
   const getValue = (item: { leak?: string; value?: string }) =>
     isDiffMetric(metric.key) ? item.leak : item.value;
 
@@ -41,25 +38,7 @@ export default function MeasureCell({ component, measure, metric }: Props) {
 
   return (
     <NumericalCell className="sw-py-3">
-      <Measure
-        metricKey={metric.key}
-        metricType={metric.type}
-        value={value}
-        small
-        ratingComponent={
-          <MetricsRatingBadge
-            label={
-              value
-                ? translateWithParameters(
-                    'metric.has_rating_X',
-                    formatMeasure(value, MetricType.Rating),
-                  )
-                : translate('metric.no_rating')
-            }
-            rating={formatMeasure(value, MetricType.Rating) as RatingLabel}
-          />
-        }
-      />
+      <Measure metricKey={metric.key} metricType={metric.type} value={value} small />
     </NumericalCell>
   );
 }
index f287b316657f7e14cbc735c8302b6609118ecb7a..9079b998acac7cd43bd0290bf424503936f79dc6 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { MetricsRatingBadge, Note, RatingLabel } from 'design-system';
+import { Note } from 'design-system';
 import React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import Measure from '../../../components/measure/Measure';
-import { translate, translateWithParameters } from '../../../helpers/l10n';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { isDiffMetric } from '../../../helpers/measures';
 import { MeasureEnhanced } from '../../../types/types';
 
@@ -33,7 +30,6 @@ interface Props {
 export default function SubnavigationMeasureValue({ measure }: Readonly<Props>) {
   const isDiff = isDiffMetric(measure.metric.key);
   const value = isDiff ? measure.leak : measure.value;
-  const formatted = formatMeasure(value, MetricType.Rating);
 
   return (
     <Note
@@ -41,17 +37,7 @@ export default function SubnavigationMeasureValue({ measure }: Readonly<Props>)
       id={`measure-${measure.metric.key}-${isDiff ? 'leak' : 'value'}`}
     >
       <Measure
-        ratingComponent={
-          <MetricsRatingBadge
-            size="xs"
-            label={
-              value
-                ? translateWithParameters('metric.has_rating_X', formatted)
-                : translate('metric.no_rating')
-            }
-            rating={formatted as RatingLabel}
-          />
-        }
+        badgeSize="xs"
         metricKey={measure.metric.key}
         metricType={measure.metric.type}
         small
index 86f41cbe60298029985f73bcee862e01942f1b0c..9a2b27300cbede32ad529fd59b1a4ed929be21c8 100644 (file)
@@ -37,6 +37,7 @@ import {
 import { isEmpty } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { formatMeasure } from '~sonar-aligned/helpers/measures';
 import { Status } from '~sonar-aligned/types/common';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
@@ -45,7 +46,6 @@ import Favorite from '../../../../components/controls/Favorite';
 import Tooltip from '../../../../components/controls/Tooltip';
 import DateFromNow from '../../../../components/intl/DateFromNow';
 import DateTimeFormatter from '../../../../components/intl/DateTimeFormatter';
-import Measure from '../../../../components/measure/Measure';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import { isDefined } from '../../../../helpers/types';
 import { getProjectUrl } from '../../../../helpers/urls';
index c8f9896b5c3e772d36378902be17f91c85a8d7f7..b34bdd750f6768e7696dd33361df3a0704071b2e 100644 (file)
@@ -26,9 +26,9 @@ import {
   RatingLabel,
 } from 'design-system';
 import * as React from 'react';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import Measure from '../../../../components/measure/Measure';
 import { duplicationRatingConverter } from '../../../../components/measure/utils';
 import { translate } from '../../../../helpers/l10n';
 import { formatRating } from '../../../../helpers/measures';
index eda6457439b4f572e363724a656caf0a85a36f33..1a587ce308b043485ca0e16c3af4600b40145351 100644 (file)
@@ -32,12 +32,12 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { isBranch } from '~sonar-aligned/helpers/branch-like';
 import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
 import withComponentContext from '../../../app/components/componentContext/withComponentContext';
 import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
 import Tooltip from '../../../components/controls/Tooltip';
-import Measure from '../../../components/measure/Measure';
 import { PopupPlacement } from '../../../components/ui/popups';
 import { translate } from '../../../helpers/l10n';
 import { BranchLike } from '../../../types/branch-like';
diff --git a/server/sonar-web/src/main/js/components/measure/Measure.tsx b/server/sonar-web/src/main/js/components/measure/Measure.tsx
deleted file mode 100644 (file)
index c760515..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * SonarQube
- * Copyright (C) 2009-2024 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 { MetricsRatingBadge, QualityGateIndicator, RatingLabel } from 'design-system';
-import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
-import { Status } from '~sonar-aligned/types/common';
-import { MetricType } from '~sonar-aligned/types/metrics';
-import Tooltip from '../../components/controls/Tooltip';
-import { translate, translateWithParameters } from '../../helpers/l10n';
-import RatingTooltipContent from './RatingTooltipContent';
-
-interface Props {
-  className?: string;
-  decimals?: number;
-  metricKey: string;
-  metricType: string;
-  small?: boolean;
-  value: string | number | undefined;
-  ratingComponent?: JSX.Element;
-}
-
-export default function Measure({
-  className,
-  decimals,
-  metricKey,
-  metricType,
-  small,
-  value,
-  ratingComponent,
-}: Props) {
-  if (value === undefined) {
-    return <span className={className}>—</span>;
-  }
-
-  if (metricType === MetricType.Level) {
-    const formatted = formatMeasure(value, MetricType.Level);
-    const ariaLabel = translateWithParameters('overview.quality_gate_x', formatted);
-
-    return (
-      <>
-        <QualityGateIndicator
-          status={(value as Status) ?? 'NONE'}
-          className="sw-mr-2"
-          ariaLabel={ariaLabel}
-          size={small ? 'sm' : 'md'}
-        />
-        <span className={small ? '' : 'sw-body-md'}>{formatted}</span>
-      </>
-    );
-  }
-
-  if (metricType !== MetricType.Rating) {
-    const formattedValue = formatMeasure(value, metricType, {
-      decimals,
-      omitExtraDecimalZeros: metricType === MetricType.Percent,
-    });
-    return <span className={className}>{formattedValue ?? '—'}</span>;
-  }
-
-  const tooltip = <RatingTooltipContent metricKey={metricKey} value={value} />;
-  const rating = ratingComponent ?? (
-    <MetricsRatingBadge
-      size={small ? 'sm' : 'md'}
-      label={
-        value
-          ? translateWithParameters('metric.has_rating_X', formatMeasure(value, MetricType.Rating))
-          : translate('metric.no_rating')
-      }
-      rating={formatMeasure(value, MetricType.Rating) as RatingLabel}
-    />
-  );
-
-  return (
-    <Tooltip overlay={tooltip}>
-      <span className={className}>{rating}</span>
-    </Tooltip>
-  );
-}
index 19e60b39226667762600ac1524a36809209e2672..74b8e77154a9eeb856b434ff7ee2b6a2f7a8c208 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import {
-  CoverageIndicator,
-  DuplicationsIndicator,
-  MetricsRatingBadge,
-  RatingEnum,
-} from 'design-system';
+import { CoverageIndicator, DuplicationsIndicator } from 'design-system';
 import * as React from 'react';
-import { formatMeasure } from '~sonar-aligned/helpers/measures';
+import Measure from '~sonar-aligned/components/measure/Measure';
 import { MetricKey, MetricType } from '~sonar-aligned/types/metrics';
-import Measure from './Measure';
 import { duplicationRatingConverter } from './utils';
 
 interface Props {
@@ -61,10 +55,5 @@ export default function MeasureIndicator(props: Props) {
     );
   }
 
-  const ratingFormatted = formatMeasure(value, MetricType.Rating);
-  const ratingComponent = (
-    <MetricsRatingBadge rating={ratingFormatted as RatingEnum} label={ratingFormatted} />
-  );
-
-  return <Measure {...props} ratingComponent={ratingComponent} />;
+  return <Measure {...props} badgeSize="sm" />;
 }
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/measure/Measure.tsx
new file mode 100644 (file)
index 0000000..b36e800
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 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 { MetricsRatingBadge, QualityGateIndicator, RatingLabel, Tooltip } from 'design-system';
+import React from 'react';
+import { useIntl } from 'react-intl';
+import { formatMeasure } from '~sonar-aligned/helpers/measures';
+import { Status } from '~sonar-aligned/types/common';
+import { MetricType } from '~sonar-aligned/types/metrics';
+import RatingTooltipContent from '../../../components/measure/RatingTooltipContent';
+
+interface Props {
+  className?: string;
+  badgeSize?: 'xs' | 'sm' | 'md';
+  decimals?: number;
+  fontClassName?: `sw-body-${string}` | `sw-heading-lg`;
+  metricKey: string;
+  metricType: string;
+  small?: boolean;
+  value: string | number | undefined;
+}
+
+export default function Measure({
+  className,
+  badgeSize,
+  decimals,
+  fontClassName,
+  metricKey,
+  metricType,
+  small,
+  value,
+}: Readonly<Props>) {
+  const intl = useIntl();
+  const classNameWithFont = classNames(className, fontClassName);
+
+  if (value === undefined) {
+    return (
+      <span
+        className={classNameWithFont}
+        aria-label={
+          metricType === MetricType.Rating ? intl.formatMessage({ id: 'metric.no_rating' }) : ''
+        }
+      >
+        —
+      </span>
+    );
+  }
+
+  if (metricType === MetricType.Level) {
+    const formatted = formatMeasure(value, MetricType.Level);
+    const ariaLabel = intl.formatMessage({ id: 'overview.quality_gate_x' }, { '0': formatted });
+
+    return (
+      <>
+        <QualityGateIndicator
+          status={(value as Status) ?? 'NONE'}
+          className="sw-mr-2"
+          ariaLabel={ariaLabel}
+          size={small ? 'sm' : 'md'}
+        />
+        <span className={small ? '' : 'sw-body-md'}>{formatted}</span>
+      </>
+    );
+  }
+
+  if (metricType !== MetricType.Rating) {
+    const formattedValue = formatMeasure(value, metricType, {
+      decimals,
+      omitExtraDecimalZeros: metricType === MetricType.Percent,
+    });
+    return <span className={classNameWithFont}>{formattedValue ?? '—'}</span>;
+  }
+
+  const tooltip = <RatingTooltipContent metricKey={metricKey} value={value} />;
+  const rating = (
+    <MetricsRatingBadge
+      size={badgeSize ?? small ? 'sm' : 'md'}
+      label={
+        value
+          ? intl.formatMessage(
+              { id: 'metric.has_rating_X' },
+              { '0': formatMeasure(value, MetricType.Rating) },
+            )
+          : intl.formatMessage({ id: 'metric.no_rating' })
+      }
+      rating={formatMeasure(value, MetricType.Rating) as RatingLabel}
+    />
+  );
+
+  return (
+    <Tooltip overlay={tooltip}>
+      <span className={className}>{rating}</span>
+    </Tooltip>
+  );
+}