diff options
author | Revanshu Paliwal <revanshu.paliwal@sonarsource.com> | 2024-06-14 17:06:14 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-06-18 20:02:41 +0000 |
commit | 50ba3a3998f109b8540cd9485cbc19b160e85d59 (patch) | |
tree | 0137930b4746fb6848d9f5bade04f40e95603b18 | |
parent | 5ff3751aa69b21ac0269eb9bc1b54625d42ecc08 (diff) | |
download | sonarqube-50ba3a3998f109b8540cd9485cbc19b160e85d59.tar.gz sonarqube-50ba3a3998f109b8540cd9485cbc19b160e85d59.zip |
SONAR-22390 Refactor PR summary to similar to overview
8 files changed, 223 insertions, 224 deletions
diff --git a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx index d8d7c24da37..def592a6601 100644 --- a/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx +++ b/server/sonar-web/src/main/js/app/components/nav/component/branch-like/CurrentBranchLikeMergeInformation.tsx @@ -31,7 +31,7 @@ export function CurrentBranchLikeMergeInformation({ }: Readonly<CurrentBranchLikeMergeInformationProps>) { return ( <span - className="sw-w-[400px] sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden sw-flex-shrink sw-min-w-0" + className="sw-max-w-[400px] sw-text-ellipsis sw-whitespace-nowrap sw-overflow-hidden sw-flex-shrink sw-min-w-0" title={translateWithParameters( 'branch_like_navigation.for_merge_into_x_from_y.title', pullRequest.target, diff --git a/server/sonar-web/src/main/js/apps/overview/branches/BranchSummaryStyles.tsx b/server/sonar-web/src/main/js/apps/overview/branches/BranchSummaryStyles.tsx index 82cfda5f355..0d4095baf8c 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/BranchSummaryStyles.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/BranchSummaryStyles.tsx @@ -54,6 +54,21 @@ export const StyleMeasuresCard = styled.div` } `; +export const StyleMeasuresCardRightBorder = styled.div` + box-sizing: border-box; + position: relative; + + &:not(:last-child):before { + content: ''; + position: absolute; + top: 0; + right: calc(var(--grids-gaps) / -2); + height: 100%; + width: 1px; + background: ${themeColor('pageBlockBorder')}; + } +`; + export const StyledConditionsCard = styled.div` box-sizing: border-box; position: relative; diff --git a/server/sonar-web/src/main/js/apps/overview/branches/FailedConditions.tsx b/server/sonar-web/src/main/js/apps/overview/branches/FailedConditions.tsx index d81e6250b12..223cbf1f836 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/FailedConditions.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/FailedConditions.tsx @@ -22,15 +22,18 @@ import _ from 'lodash'; import * as React from 'react'; import { FormattedMessage } from 'react-intl'; import { isDiffMetric } from '../../../helpers/measures'; -import { QualityGateStatus } from '../../../types/quality-gates'; -import { QualityGate } from '../../../types/types'; +import { BranchLike } from '../../../types/branch-like'; +import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates'; +import { Component, QualityGate } from '../../../types/types'; import ZeroNewIssuesSimplificationGuide from '../components/ZeroNewIssuesSimplificationGuide'; import QualityGateConditions from './QualityGateConditions'; export interface FailedConditionsProps { + branchLike?: BranchLike; + component: Pick<Component, 'key'>; + failedConditions: QualityGateStatusConditionEnhanced[]; isApplication?: boolean; isNewCode: boolean; - qgStatus: QualityGateStatus; qualityGate?: QualityGate; } @@ -38,9 +41,10 @@ export default function FailedConditions({ isApplication, isNewCode, qualityGate, - qgStatus, + failedConditions, + component, + branchLike, }: FailedConditionsProps) { - const { failedConditions, branchLike } = qgStatus; const [newCodeFailedConditions, overallFailedConditions] = _.partition( failedConditions, (condition) => isDiffMetric(condition.metric), @@ -70,7 +74,7 @@ export default function FailedConditions({ <ZeroNewIssuesSimplificationGuide qualityGate={qualityGate} /> )} <QualityGateConditions - component={qgStatus} + component={component} branchLike={branchLike} failedConditions={isNewCode ? newCodeFailedConditions : overallFailedConditions} isBuiltInQualityGate={isNewCode && qualityGate?.isBuiltIn} diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx index 985cfa72f48..fb1dd98d321 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanel.tsx @@ -38,8 +38,8 @@ export interface QualityGatePanelProps { loading?: boolean; qgStatuses?: QualityGateStatus[]; qualityGate?: QualityGate; - showCaycWarningInApp: boolean; - showCaycWarningInProject: boolean; + showCaycWarningInApp?: boolean; + showCaycWarningInProject?: boolean; totalFailedConditionLength: number; } @@ -51,8 +51,8 @@ export function QualityGatePanel(props: QualityGatePanelProps) { qualityGate, isNewCode = false, totalFailedConditionLength, - showCaycWarningInProject, - showCaycWarningInApp, + showCaycWarningInProject = false, + showCaycWarningInApp = false, } = props; if (qgStatuses === undefined) { diff --git a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx index df91989c4a8..64993e86a8f 100644 --- a/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx +++ b/server/sonar-web/src/main/js/apps/overview/branches/QualityGatePanelSection.tsx @@ -64,7 +64,9 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) { isNewCode={isNewCode} isApplication={isApplication} qualityGate={qualityGate} - qgStatus={qgStatus} + failedConditions={qgStatus.failedConditions} + branchLike={qgStatus.branchLike} + component={qgStatus} /> </BorderlessAccordion> @@ -75,7 +77,9 @@ export function QualityGatePanelSection(props: QualityGatePanelSectionProps) { isNewCode={isNewCode} isApplication={isApplication} qualityGate={qualityGate} - qgStatus={qgStatus} + failedConditions={qgStatus.failedConditions} + branchLike={qgStatus.branchLike} + component={qgStatus} /> )} </> diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx deleted file mode 100644 index 7f77a7d81a1..00000000000 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/IssueMeasuresCard.tsx +++ /dev/null @@ -1,173 +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 styled from '@emotion/styled'; -import { - HelperHintIcon, - LightGreyCard, - LightLabel, - SnoozeCircleIcon, - TextError, - TextSubdued, - TrendDownCircleIcon, - TrendUpCircleIcon, - themeColor, -} from 'design-system'; -import * as React from 'react'; -import { useIntl } from 'react-intl'; -import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like'; -import { formatMeasure } from '~sonar-aligned/helpers/measures'; -import { getComponentIssuesUrl } from '~sonar-aligned/helpers/urls'; -import { MetricKey, MetricType } from '~sonar-aligned/types/metrics'; -import Tooltip from '../../../components/controls/Tooltip'; -import { getLeakValue } from '../../../components/measure/utils'; -import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils'; -import { findMeasure } from '../../../helpers/measures'; -import { PullRequest } from '../../../types/branch-like'; -import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates'; -import { Component, MeasureEnhanced } from '../../../types/types'; -import { IssueMeasuresCardInner } from '../components/IssueMeasuresCardInner'; -import { Status, getConditionRequiredLabel } from '../utils'; - -interface Props { - component: Component; - conditions: QualityGateStatusConditionEnhanced[]; - measures: MeasureEnhanced[]; - pullRequest: PullRequest; -} - -export default function IssueMeasuresCard( - props: React.PropsWithChildren<Props & React.HTMLAttributes<HTMLDivElement>>, -) { - const { measures, conditions, component, pullRequest, ...rest } = props; - - const intl = useIntl(); - - const issuesCount = getLeakValue(findMeasure(measures, MetricKey.new_violations)); - const issuesCondition = conditions.find((c) => c.metric === MetricKey.new_violations); - const issuesConditionFailed = issuesCondition?.level === Status.ERROR; - const fixedCount = findMeasure(measures, MetricKey.pull_request_fixed_issues)?.value; - const acceptedCount = getLeakValue(findMeasure(measures, MetricKey.new_accepted_issues)); - - const issuesUrl = getComponentIssuesUrl(component.key, { - ...getBranchLikeQuery(pullRequest), - ...DEFAULT_ISSUES_QUERY, - }); - const fixedUrl = getComponentIssuesUrl(component.key, { - fixedInPullRequest: pullRequest.key, - }); - const acceptedUrl = getComponentIssuesUrl(component.key, { - ...getBranchLikeQuery(pullRequest), - ...DEFAULT_ISSUES_QUERY, - issueStatuses: 'ACCEPTED', - }); - - return ( - <LightGreyCard className="sw-p-8 sw-rounded-2 sw-flex sw-text-base sw-gap-4" {...rest}> - <IssueMeasuresCardInner - className="sw-w-1/3" - header={intl.formatMessage({ id: 'overview.new_issues' })} - data-testid={`overview__measures-${MetricKey.new_violations}`} - data-guiding-id={issuesConditionFailed ? 'overviewZeroNewIssuesSimplification' : undefined} - metric={MetricKey.new_violations} - value={formatMeasure(issuesCount, MetricType.ShortInteger)} - url={issuesUrl} - failed={issuesConditionFailed} - icon={issuesConditionFailed && <TrendUpCircleIcon />} - footer={ - issuesCondition && - (issuesConditionFailed ? ( - <TextError - className="sw-font-regular sw-body-xs sw-inline" - text={getConditionRequiredLabel(issuesCondition, intl, true)} - /> - ) : ( - <LightLabel className="sw-body-xs"> - {getConditionRequiredLabel(issuesCondition, intl)} - </LightLabel> - )) - } - /> - <StyledCardSeparator /> - <IssueMeasuresCardInner - className="sw-w-1/3" - header={intl.formatMessage({ id: 'overview.accepted_issues' })} - data-testid={`overview__measures-${MetricKey.new_accepted_issues}`} - metric={MetricKey.new_accepted_issues} - value={formatMeasure(acceptedCount, MetricType.ShortInteger)} - disabled={component.needIssueSync} - url={acceptedUrl} - icon={ - acceptedCount && ( - <SnoozeCircleIcon - color={acceptedCount === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'} - /> - ) - } - footer={ - <TextSubdued className="sw-body-xs"> - {intl.formatMessage({ id: 'overview.accepted_issues.help' })} - </TextSubdued> - } - /> - <StyledCardSeparator /> - <IssueMeasuresCardInner - className="sw-w-1/3" - header={ - <> - {intl.formatMessage({ id: 'overview.pull_request.fixed_issues' })} - <Tooltip - content={ - <div className="sw-flex sw-flex-col sw-gap-4"> - <span> - {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.disclaimer' })} - </span> - <span> - {intl.formatMessage({ - id: 'overview.pull_request.fixed_issues.disclaimer.2', - })} - </span> - </div> - } - side="top" - > - <HelperHintIcon raised /> - </Tooltip> - </> - } - data-testid={`overview__measures-${MetricKey.pull_request_fixed_issues}`} - metric={MetricKey.pull_request_fixed_issues} - value={formatMeasure(fixedCount, MetricType.ShortInteger)} - disabled={component.needIssueSync} - url={fixedUrl} - icon={fixedCount && fixedCount !== '0' && <TrendDownCircleIcon />} - footer={ - <TextSubdued className="sw-body-xs"> - {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.help' })} - </TextSubdued> - } - /> - </LightGreyCard> - ); -} - -const StyledCardSeparator = styled.div` - width: 1px; - background-color: ${themeColor('projectCardBorder')}; -`; diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx index fc313e846e2..14bb087b4e5 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/MeasuresCardPanel.tsx @@ -18,22 +18,51 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ import classNames from 'classnames'; +import { + Card, + HelperHintIcon, + LightLabel, + SnoozeCircleIcon, + TextError, + TextSubdued, + TrendDownCircleIcon, + TrendUpCircleIcon, +} from 'design-system/lib'; import * as React from 'react'; -import { getComponentSecurityHotspotsUrl } from '~sonar-aligned/helpers/urls'; -import { MetricKey } from '~sonar-aligned/types/metrics'; +import { useIntl } from 'react-intl'; +import { + getComponentIssuesUrl, + getComponentSecurityHotspotsUrl, +} from '~sonar-aligned/helpers/urls'; +import { MetricKey, MetricType } from '~sonar-aligned/types/metrics'; +import Tooltip from '../../../components/controls/Tooltip'; import { getLeakValue } from '../../../components/measure/utils'; +import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils'; import { findMeasure } from '../../../helpers/measures'; import { getComponentDrilldownUrl } from '../../../helpers/urls'; +import { getBranchLikeQuery } from '../../../sonar-aligned/helpers/branch-like'; +import { formatMeasure } from '../../../sonar-aligned/helpers/measures'; import { PullRequest } from '../../../types/branch-like'; import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates'; import { Component, MeasureEnhanced } from '../../../types/types'; +import { + GridContainer, + StyleMeasuresCard, + StyleMeasuresCardRightBorder, + StyledConditionsCard, +} from '../branches/BranchSummaryStyles'; +import FailedConditions from '../branches/FailedConditions'; +import { IssueMeasuresCardInner } from '../components/IssueMeasuresCardInner'; import MeasuresCardNumber from '../components/MeasuresCardNumber'; import MeasuresCardPercent from '../components/MeasuresCardPercent'; -import { MeasurementType, getMeasurementMetricKey } from '../utils'; -import IssueMeasuresCard from './IssueMeasuresCard'; +import { + MeasurementType, + Status, + getConditionRequiredLabel, + getMeasurementMetricKey, +} from '../utils'; interface Props { - className?: string; component: Component; conditions: QualityGateStatusConditionEnhanced[]; measures: MeasureEnhanced[]; @@ -41,23 +70,144 @@ interface Props { } export default function MeasuresCardPanel(props: React.PropsWithChildren<Props>) { - const { pullRequest, component, measures, conditions, className } = props; + const { pullRequest, component, measures, conditions } = props; const newSecurityHotspots = getLeakValue( findMeasure(measures, MetricKey.new_security_hotspots), ) as string; - return ( - <> - <IssueMeasuresCard - conditions={conditions} - measures={measures} - component={component} - pullRequest={pullRequest} - /> + const intl = useIntl(); + + const issuesCount = getLeakValue(findMeasure(measures, MetricKey.new_violations)); + const issuesCondition = conditions.find((c) => c.metric === MetricKey.new_violations); + const isIssuesConditionFailed = issuesCondition?.level === Status.ERROR; + const fixedCount = findMeasure(measures, MetricKey.pull_request_fixed_issues)?.value; + const acceptedCount = getLeakValue(findMeasure(measures, MetricKey.new_accepted_issues)); + + const issuesUrl = getComponentIssuesUrl(component.key, { + ...getBranchLikeQuery(pullRequest), + ...DEFAULT_ISSUES_QUERY, + }); + const fixedUrl = getComponentIssuesUrl(component.key, { + fixedInPullRequest: pullRequest.key, + }); + const acceptedUrl = getComponentIssuesUrl(component.key, { + ...getBranchLikeQuery(pullRequest), + ...DEFAULT_ISSUES_QUERY, + issueStatuses: 'ACCEPTED', + }); - <div className={classNames('sw-w-full sw-flex sw-flex-row sw-gap-4 sw-mt-4', className)}> - <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4"> + const totalFailedConditions = conditions.filter((condition) => condition.level === Status.ERROR); + + return ( + <Card> + <GridContainer + className={classNames('sw-relative sw-overflow-hidden sw-mt-8 js-summary', { + 'sw-grid-cols-3': totalFailedConditions.length === 0, + 'sw-grid-cols-4': totalFailedConditions.length > 0, + })} + > + {totalFailedConditions.length > 0 && ( + <StyledConditionsCard className="sw-row-span-3"> + <FailedConditions + branchLike={pullRequest} + failedConditions={totalFailedConditions} + isNewCode + component={component} + /> + </StyledConditionsCard> + )} + <StyleMeasuresCard> + <IssueMeasuresCardInner + header={intl.formatMessage({ id: 'overview.new_issues' })} + data-testid={`overview__measures-${MetricKey.new_violations}`} + data-guiding-id={ + isIssuesConditionFailed ? 'overviewZeroNewIssuesSimplification' : undefined + } + metric={MetricKey.new_violations} + value={formatMeasure(issuesCount, MetricType.ShortInteger)} + url={issuesUrl} + failed={isIssuesConditionFailed} + icon={isIssuesConditionFailed && <TrendUpCircleIcon />} + footer={ + issuesCondition && + (isIssuesConditionFailed ? ( + <TextError + className="sw-font-regular sw-body-xs sw-inline" + text={getConditionRequiredLabel(issuesCondition, intl, true)} + /> + ) : ( + <LightLabel className="sw-body-xs"> + {getConditionRequiredLabel(issuesCondition, intl)} + </LightLabel> + )) + } + /> + </StyleMeasuresCard> + <StyleMeasuresCard> + <IssueMeasuresCardInner + header={intl.formatMessage({ id: 'overview.accepted_issues' })} + data-testid={`overview__measures-${MetricKey.new_accepted_issues}`} + metric={MetricKey.new_accepted_issues} + value={formatMeasure(acceptedCount, MetricType.ShortInteger)} + disabled={component.needIssueSync} + url={acceptedUrl} + icon={ + acceptedCount && ( + <SnoozeCircleIcon + color={ + acceptedCount === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon' + } + /> + ) + } + footer={ + <TextSubdued className="sw-body-xs"> + {intl.formatMessage({ id: 'overview.accepted_issues.help' })} + </TextSubdued> + } + /> + </StyleMeasuresCard> + <StyleMeasuresCard> + <IssueMeasuresCardInner + header={ + <> + {intl.formatMessage({ id: 'overview.pull_request.fixed_issues' })} + <Tooltip + content={ + <div className="sw-flex sw-flex-col sw-gap-4"> + <span> + {intl.formatMessage({ + id: 'overview.pull_request.fixed_issues.disclaimer', + })} + </span> + <span> + {intl.formatMessage({ + id: 'overview.pull_request.fixed_issues.disclaimer.2', + })} + </span> + </div> + } + side="top" + > + <HelperHintIcon raised /> + </Tooltip> + </> + } + data-testid={`overview__measures-${MetricKey.pull_request_fixed_issues}`} + metric={MetricKey.pull_request_fixed_issues} + value={formatMeasure(fixedCount, MetricType.ShortInteger)} + disabled={component.needIssueSync} + url={fixedUrl} + icon={fixedCount && fixedCount !== '0' && <TrendDownCircleIcon />} + footer={ + <TextSubdued className="sw-body-xs"> + {intl.formatMessage({ id: 'overview.pull_request.fixed_issues.help' })} + </TextSubdued> + } + /> + </StyleMeasuresCard> + <StyleMeasuresCardRightBorder> <MeasuresCardPercent componentKey={component.key} branchLike={pullRequest} @@ -77,23 +227,8 @@ export default function MeasuresCardPanel(props: React.PropsWithChildren<Props>) showRequired useDiffMetric /> - - <MeasuresCardNumber - label={ - newSecurityHotspots === '1' - ? 'issue.type.SECURITY_HOTSPOT' - : 'issue.type.SECURITY_HOTSPOT.plural' - } - url={getComponentSecurityHotspotsUrl(component.key, pullRequest)} - value={newSecurityHotspots} - metric={MetricKey.new_security_hotspots} - conditions={conditions} - conditionMetric={MetricKey.new_security_hotspots_reviewed} - showRequired - /> - </div> - - <div className="sw-flex-1 sw-flex sw-flex-col sw-gap-4"> + </StyleMeasuresCardRightBorder> + <StyleMeasuresCardRightBorder> <MeasuresCardPercent componentKey={component.key} branchLike={pullRequest} @@ -113,8 +248,23 @@ export default function MeasuresCardPanel(props: React.PropsWithChildren<Props>) useDiffMetric showRequired /> + </StyleMeasuresCardRightBorder> + <div> + <MeasuresCardNumber + label={ + newSecurityHotspots === '1' + ? 'issue.type.SECURITY_HOTSPOT' + : 'issue.type.SECURITY_HOTSPOT.plural' + } + url={getComponentSecurityHotspotsUrl(component.key, pullRequest)} + value={newSecurityHotspots} + metric={MetricKey.new_security_hotspots} + conditions={conditions} + conditionMetric={MetricKey.new_security_hotspots_reviewed} + showRequired + /> </div> - </div> - </> + </GridContainer> + </Card> ); } diff --git a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx index dc1954991d0..e5778e1bd48 100644 --- a/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx +++ b/server/sonar-web/src/main/js/apps/overview/pullRequests/PullRequestOverview.tsx @@ -98,8 +98,6 @@ export default function PullRequestOverview(props: Readonly<Readonly<Props>>) { <PullRequestMetaTopBar pullRequest={pullRequest} measures={measures} /> <BasicSeparator className="sw-my-4" /> - <AnalysisStatus className="sw-mb-4" component={component} /> - {ignoredConditions && <IgnoredConditionWarning />} <div className="sw-flex sw-justify-between sw-items-start sw-my-6"> @@ -107,8 +105,9 @@ export default function PullRequestOverview(props: Readonly<Readonly<Props>>) { <LastAnalysisLabel analysisDate={pullRequest.analysisDate} /> </div> + <AnalysisStatus className="sw-mb-4" component={component} /> + <MeasuresCardPanel - className="sw-flex-1" pullRequest={pullRequest} component={component} conditions={enhancedConditions} |