You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

OverallCodeMeasuresPanel.tsx 5.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154
  1. /*
  2. * SonarQube
  3. * Copyright (C) 2009-2024 SonarSource SA
  4. * mailto:info AT sonarsource DOT com
  5. *
  6. * This program is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public
  8. * License as published by the Free Software Foundation; either
  9. * version 3 of the License, or (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  14. * Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program; if not, write to the Free Software Foundation,
  18. * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  19. */
  20. import {
  21. MetricsRatingBadge,
  22. NoDataIcon,
  23. SnoozeCircleIcon,
  24. TextSubdued,
  25. getTabPanelId,
  26. } from 'design-system';
  27. import * as React from 'react';
  28. import { useIntl } from 'react-intl';
  29. import { getBranchLikeQuery } from '../../../helpers/branch-like';
  30. import { findMeasure, formatMeasure, formatRating } from '../../../helpers/measures';
  31. import {
  32. CodeScope,
  33. getComponentIssuesUrl,
  34. getComponentSecurityHotspotsUrl,
  35. } from '../../../helpers/urls';
  36. import { Branch } from '../../../types/branch-like';
  37. import { SoftwareQuality } from '../../../types/clean-code-taxonomy';
  38. import { isApplication } from '../../../types/component';
  39. import { IssueStatus } from '../../../types/issues';
  40. import { MetricKey, MetricType } from '../../../types/metrics';
  41. import { QualityGateStatus } from '../../../types/quality-gates';
  42. import { Component, MeasureEnhanced } from '../../../types/types';
  43. import MeasuresCard from '../components/MeasuresCard';
  44. import MeasuresCardNumber from '../components/MeasuresCardNumber';
  45. import MeasuresPanelPercentCards from './MeasuresPanelPercentCards';
  46. import SoftwareImpactMeasureCard from './SoftwareImpactMeasureCard';
  47. export interface OverallCodeMeasuresPanelProps {
  48. branch?: Branch;
  49. component: Component;
  50. measures: MeasureEnhanced[];
  51. qgStatuses?: QualityGateStatus[];
  52. }
  53. export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeasuresPanelProps>) {
  54. const { branch, qgStatuses, component, measures } = props;
  55. const intl = useIntl();
  56. const isApp = isApplication(component.qualifier);
  57. const conditions = qgStatuses?.flatMap((qg) => qg.conditions) ?? [];
  58. const acceptedIssues = findMeasure(measures, MetricKey.accepted_issues)?.value;
  59. const securityHotspots = findMeasure(measures, MetricKey.security_hotspots)?.value;
  60. const securityRating = findMeasure(measures, MetricKey.security_review_rating)?.value;
  61. return (
  62. <div id={getTabPanelId(CodeScope.Overall)} className="sw-mt-6">
  63. <div className="sw-flex sw-gap-4">
  64. <SoftwareImpactMeasureCard
  65. branch={branch}
  66. component={component}
  67. conditions={conditions}
  68. softwareQuality={SoftwareQuality.Security}
  69. ratingMetricKey={MetricKey.security_rating}
  70. measures={measures}
  71. />
  72. <SoftwareImpactMeasureCard
  73. branch={branch}
  74. component={component}
  75. conditions={conditions}
  76. softwareQuality={SoftwareQuality.Reliability}
  77. ratingMetricKey={MetricKey.reliability_rating}
  78. measures={measures}
  79. />
  80. <SoftwareImpactMeasureCard
  81. branch={branch}
  82. component={component}
  83. conditions={conditions}
  84. softwareQuality={SoftwareQuality.Maintainability}
  85. ratingMetricKey={MetricKey.sqale_rating}
  86. measures={measures}
  87. />
  88. </div>
  89. <div className="sw-grid sw-grid-cols-2 sw-gap-4 sw-mt-4">
  90. <MeasuresCard
  91. url={getComponentIssuesUrl(component.key, {
  92. ...getBranchLikeQuery(branch),
  93. issueStatuses: IssueStatus.Accepted,
  94. })}
  95. value={formatMeasure(acceptedIssues, MetricType.ShortInteger)}
  96. metric={MetricKey.accepted_issues}
  97. label="overview.accepted_issues"
  98. failed={false}
  99. icon={
  100. <SnoozeCircleIcon
  101. color={acceptedIssues === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'}
  102. />
  103. }
  104. >
  105. <TextSubdued className="sw-body-xs sw-mt-3">
  106. {intl.formatMessage({
  107. id: 'overview.accepted_issues.help',
  108. })}
  109. </TextSubdued>
  110. </MeasuresCard>
  111. <MeasuresPanelPercentCards
  112. branch={branch}
  113. component={component}
  114. measures={measures}
  115. conditions={conditions}
  116. />
  117. <MeasuresCardNumber
  118. label={
  119. securityHotspots === '1'
  120. ? 'issue.type.SECURITY_HOTSPOT'
  121. : 'issue.type.SECURITY_HOTSPOT.plural'
  122. }
  123. url={getComponentSecurityHotspotsUrl(component.key, {
  124. ...getBranchLikeQuery(branch),
  125. })}
  126. value={securityHotspots}
  127. metric={MetricKey.security_hotspots}
  128. conditions={conditions}
  129. conditionMetric={MetricKey.security_hotspots_reviewed}
  130. showRequired={!isApp}
  131. icon={
  132. securityRating ? (
  133. <MetricsRatingBadge
  134. label={securityRating}
  135. rating={formatRating(securityRating)}
  136. size="md"
  137. />
  138. ) : (
  139. <NoDataIcon size="md" />
  140. )
  141. }
  142. />
  143. </div>
  144. </div>
  145. );
  146. }