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}
useDiffMetric={useDiffMetric}
showRequired={!isApp}
/>
- </div>
+ </>
);
}
import {
LightGreyCard,
LightLabel,
+ MetricsRatingBadge,
+ NoDataIcon,
SnoozeCircleIcon,
TextError,
TextSubdued,
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';
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) {
}
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}
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>
);
}
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">
</TextSubdued>
</MeasuresCard>
+ <MeasuresPanelPercentCards
+ branch={branch}
+ component={component}
+ measures={measures}
+ failedConditions={failedConditions}
+ />
+
<MeasuresCardNumber
label={
securityHotspots === '1'
}
/>
</div>
-
- <MeasuresPanelPercentCards
- branch={branch}
- component={component}
- measures={measures}
- failedConditions={failedConditions}
- />
</div>
);
}
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">
const intl = useIntl();
const condition = conditions.find((condition) => condition.metric === conditionMetric);
-
const conditionFailed = condition?.level === Status.ERROR;
return (
* 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,
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)}
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}
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)}