]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-21455 Reposition cards on branch overview
authorstanislavh <stanislav.honcharov@sonarsource.com>
Thu, 1 Feb 2024 13:34:02 +0000 (14:34 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 1 Feb 2024 20:02:48 +0000 (20:02 +0000)
server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelPercentCards.tsx
server/sonar-web/src/main/js/apps/overview/branches/NewCodeMeasuresPanel.tsx
server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx
server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx
server/sonar-web/src/main/js/apps/overview/components/MeasuresCardNumber.tsx
server/sonar-web/src/main/js/apps/overview/components/MeasuresCardPercent.tsx

index d8721359cdd3f544df54f7957782ed53f84c3bb9..b27c94833ffc7d169602de2fb79e80843980d42e 100644 (file)
@@ -44,7 +44,7 @@ export default function MeasuresPanelPercentCards(props: Readonly<Props>) {
   const isApp = isApplication(component.qualifier);
 
   return (
-    <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
+    <>
       <MeasuresCardPercent
         branchLike={branch}
         componentKey={component.key}
@@ -86,6 +86,6 @@ export default function MeasuresPanelPercentCards(props: Readonly<Props>) {
         useDiffMetric={useDiffMetric}
         showRequired={!isApp}
       />
-    </div>
+    </>
   );
 }
index 172eb8717ba4cca302c5990b1821332f0aa62687..a127bf27f2d7e0d4fbaaad730ed2bfdaf6c413a0 100644 (file)
@@ -21,6 +21,8 @@ import styled from '@emotion/styled';
 import {
   LightGreyCard,
   LightLabel,
+  MetricsRatingBadge,
+  NoDataIcon,
   SnoozeCircleIcon,
   TextError,
   TextSubdued,
@@ -33,7 +35,7 @@ import { getTabPanelId } from '../../../components/controls/BoxedTabs';
 import { getLeakValue } from '../../../components/measure/utils';
 import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
 import { getBranchLikeQuery } from '../../../helpers/branch-like';
-import { findMeasure, formatMeasure } from '../../../helpers/measures';
+import { findMeasure, formatMeasure, formatRating } from '../../../helpers/measures';
 import { getComponentIssuesUrl, getComponentSecurityHotspotsUrl } from '../../../helpers/urls';
 import { Branch } from '../../../types/branch-like';
 import { isApplication } from '../../../types/component';
@@ -68,6 +70,9 @@ export default function NewCodeMeasuresPanel(props: Readonly<Props>) {
   const newSecurityHotspots = getLeakValue(
     findMeasure(measures, MetricKey.new_security_hotspots),
   ) as string;
+  const newSecurityReviewRating = getLeakValue(
+    findMeasure(measures, MetricKey.new_security_review_rating),
+  );
 
   let issuesFooter;
   if (newIssuesCondition && !isApp) {
@@ -104,8 +109,8 @@ export default function NewCodeMeasuresPanel(props: Readonly<Props>) {
   }
 
   return (
-    <div className="sw-mt-6" id={getTabPanelId(MeasuresTabs.New)}>
-      <LightGreyCard className="sw-flex sw-rounded-2 sw-gap-4">
+    <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-6" id={getTabPanelId(MeasuresTabs.New)}>
+      <LightGreyCard className="sw-flex sw-col-span-2 sw-rounded-2 sw-gap-4">
         <IssueMeasuresCardInner
           data-testid="overview__measures-new_issues"
           disabled={component.needIssueSync}
@@ -158,23 +163,32 @@ export default function NewCodeMeasuresPanel(props: Readonly<Props>) {
         failedConditions={failedConditions}
       />
 
-      <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
-        <MeasuresCardNumber
-          label={
-            newSecurityHotspots === '1'
-              ? 'issue.type.SECURITY_HOTSPOT'
-              : 'issue.type.SECURITY_HOTSPOT.plural'
-          }
-          url={getComponentSecurityHotspotsUrl(component.key, {
-            ...getBranchLikeQuery(branch),
-          })}
-          value={newSecurityHotspots}
-          metric={MetricKey.new_security_hotspots}
-          conditions={conditions}
-          conditionMetric={MetricKey.new_security_hotspots_reviewed}
-          showRequired={!isApp}
-        />
-      </div>
+      <MeasuresCardNumber
+        label={
+          newSecurityHotspots === '1'
+            ? 'issue.type.SECURITY_HOTSPOT'
+            : 'issue.type.SECURITY_HOTSPOT.plural'
+        }
+        url={getComponentSecurityHotspotsUrl(component.key, {
+          ...getBranchLikeQuery(branch),
+        })}
+        value={newSecurityHotspots}
+        metric={MetricKey.new_security_hotspots}
+        conditions={conditions}
+        conditionMetric={MetricKey.new_security_hotspots_reviewed}
+        showRequired={!isApp}
+        icon={
+          newSecurityReviewRating ? (
+            <MetricsRatingBadge
+              label={newSecurityReviewRating}
+              rating={formatRating(newSecurityReviewRating)}
+              size="md"
+            />
+          ) : (
+            <NoDataIcon size="md" />
+          )
+        }
+      />
     </div>
   );
 }
index 1d66c017c3e68ccebba36dbc63ab6cca65759ccd..5699c44722b8743e41760d0447400181e761e0dc 100644 (file)
@@ -60,7 +60,7 @@ export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeas
   const failedConditions = qgStatuses?.flatMap((qg) => qg.failedConditions) ?? [];
   const acceptedIssues = findMeasure(measures, MetricKey.accepted_issues)?.value;
   const securityHotspots = findMeasure(measures, MetricKey.security_hotspots)?.value;
-  const securityRating = findMeasure(measures, MetricKey.security_rating)?.value;
+  const securityRating = findMeasure(measures, MetricKey.security_review_rating)?.value;
 
   return (
     <div id={getTabPanelId(MeasuresTabs.Overall)} className="sw-mt-6">
@@ -110,6 +110,13 @@ export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeas
           </TextSubdued>
         </MeasuresCard>
 
+        <MeasuresPanelPercentCards
+          branch={branch}
+          component={component}
+          measures={measures}
+          failedConditions={failedConditions}
+        />
+
         <MeasuresCardNumber
           label={
             securityHotspots === '1'
@@ -137,13 +144,6 @@ export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeas
           }
         />
       </div>
-
-      <MeasuresPanelPercentCards
-        branch={branch}
-        component={component}
-        measures={measures}
-        failedConditions={failedConditions}
-      />
     </div>
   );
 }
index 68c6174487bd2eab164923b52a721516f8791531..9fadf2286f8bd0704fb4b0b08ff766dc74870e30 100644 (file)
@@ -42,7 +42,7 @@ export default function MeasuresCard(
   const { failed, children, metric, icon, value, url, label, disabled, tooltip, ...rest } = props;
 
   return (
-    <StyledCard className="sw-h-fit sw-p-6 sw-rounded-2 sw-text-base" {...rest}>
+    <StyledCard className="sw-p-6 sw-rounded-2 sw-text-base" {...rest}>
       <ColorBold className="sw-body-sm-highlight">{translate(label)}</ColorBold>
       {failed && (
         <Badge className="sw-mt-1/2 sw-px-1 sw-ml-2" variant="deleted">
index 1c48863a3f7fb8a122603239d707106429d5d0ea..feea138e269ab003c0e233e746c756af1cdbe3eb 100644 (file)
@@ -44,7 +44,6 @@ export default function MeasuresCardNumber(
   const intl = useIntl();
 
   const condition = conditions.find((condition) => condition.metric === conditionMetric);
-
   const conditionFailed = condition?.level === Status.ERROR;
 
   return (
index d3b6eb96e263f10456a3bd6874ea6d595b88b412..fa181275dfe461d97bcf9515bcc9d264c40dc98b 100644 (file)
@@ -17,6 +17,7 @@
  * 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 {
   ContentLink,
   CoverageIndicator,
@@ -97,6 +98,8 @@ export default function MeasuresCardPercent(
   const condition = conditions.find((c) => c.metric === conditionMetric);
   const conditionFailed = condition?.level === Status.ERROR;
 
+  const shouldRenderRequiredLabel = showRequired && condition;
+
   return (
     <MeasuresCard
       value={formatMeasure(value, MetricType.Percent)}
@@ -106,21 +109,25 @@ export default function MeasuresCardPercent(
       failed={conditionFailed}
       icon={renderIcon(measurementType, value)}
     >
-      <span className="sw-body-xs sw-mt-3">
-        {showRequired &&
-          condition &&
-          (conditionFailed ? (
+      {shouldRenderRequiredLabel && (
+        <span className="sw-body-xs sw-mt-3">
+          {conditionFailed ? (
             <TextError
               className="sw-font-regular sw-inline"
               text={getConditionRequiredLabel(condition, intl, true)}
             />
           ) : (
             <LightLabel>{getConditionRequiredLabel(condition, intl)}</LightLabel>
-          ))}
-      </span>
-
-      <div className="sw-flex sw-body-sm sw-justify-between sw-items-center sw-mt-1">
-        <LightLabel className="sw-flex sw-items-center sw-gap-1 ">
+          )}
+        </span>
+      )}
+      <div
+        className={classNames('sw-flex sw-body-xs sw-justify-between sw-items-center', {
+          'sw-mt-1': shouldRenderRequiredLabel,
+          'sw-mt-3': !shouldRenderRequiredLabel,
+        })}
+      >
+        <LightLabel className="sw-flex sw-gap-1">
           <FormattedMessage
             defaultMessage={translate(linesLabel)}
             id={linesLabel}
@@ -132,7 +139,7 @@ export default function MeasuresCardPercent(
                     linesValue ?? '0',
                     localizeMetric(linesMetric),
                   )}
-                  className="sw-body-md-highlight sw-text-lg"
+                  className="sw-body-sm-highlight sw--mt-[3px]"
                   to={linesUrl}
                 >
                   {formatMeasure(linesValue ?? '0', MetricType.ShortInteger)}