aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--server/sonar-web/design-system/src/components/Link.tsx15
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx3
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureBreakdownCard.tsx1
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx45
-rw-r--r--server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx35
-rw-r--r--server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx31
6 files changed, 93 insertions, 37 deletions
diff --git a/server/sonar-web/design-system/src/components/Link.tsx b/server/sonar-web/design-system/src/components/Link.tsx
index edd9f192a40..d97489785d7 100644
--- a/server/sonar-web/design-system/src/components/Link.tsx
+++ b/server/sonar-web/design-system/src/components/Link.tsx
@@ -155,11 +155,14 @@ export const NakedLink = styled(BaseLink)`
font-weight: 600;
color: ${themeColor('linkNaked')};
- &:hover,
- &:focus,
- &:active {
- color: ${themeColor('linkActive')};
- }
+ ${({ disabled, theme }) =>
+ disabled
+ ? tw`sw-cursor-default`
+ : `&:hover,
+ &:focus,
+ &:active {
+ color: ${themeColor('linkActive')({ theme })};
+ }`};
`;
export const DrilldownLink = styled(StyledBaseLink)`
@@ -219,6 +222,8 @@ export const DiscreetLinkBox = styled(StyledBaseLink)`
background-color: none;
display: block;
}
+
+ ${({ disabled }) => (disabled ? tw`sw-cursor-default` : '')};
`;
LinkBox.displayName = 'DiscreetLinkBox';
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx b/server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx
index 4c228520cc7..1d66c017c3e 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/OverallCodeMeasuresPanel.tsx
@@ -38,6 +38,7 @@ import { QualityGateStatus } from '../../../types/quality-gates';
import { Component, MeasureEnhanced } from '../../../types/types';
import MeasuresCard from '../components/MeasuresCard';
import MeasuresCardNumber from '../components/MeasuresCardNumber';
+import { OverviewDisabledLinkTooltip } from '../components/OverviewDisabledLinkTooltip';
import { MeasuresTabs } from '../utils';
import MeasuresPanelPercentCards from './MeasuresPanelPercentCards';
import SoftwareImpactMeasureCard from './SoftwareImpactMeasureCard';
@@ -99,6 +100,8 @@ export default function OverallCodeMeasuresPanel(props: Readonly<OverallCodeMeas
color={acceptedIssues === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'}
/>
}
+ disabled={component.needIssueSync}
+ tooltip={component.needIssueSync ? <OverviewDisabledLinkTooltip /> : null}
>
<TextSubdued className="sw-body-xs sw-mt-3">
{intl.formatMessage({
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureBreakdownCard.tsx b/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureBreakdownCard.tsx
index d8755ae82ad..fcab9056e65 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureBreakdownCard.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureBreakdownCard.tsx
@@ -92,6 +92,7 @@ export function SoftwareImpactMeasureBreakdownCard(
}),
},
)}
+ disabled={component.needIssueSync}
to={url}
>
<span>{formatMeasure(value, MetricType.ShortInteger)}</span>
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx b/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx
index d0ea22018fb..3d7bab789e5 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/SoftwareImpactMeasureCard.tsx
@@ -29,6 +29,7 @@ import {
} from 'design-system';
import * as React from 'react';
import { useIntl } from 'react-intl';
+import Tooltip from '../../../components/controls/Tooltip';
import { DEFAULT_ISSUES_QUERY } from '../../../components/shared/utils';
import { formatMeasure } from '../../../helpers/measures';
import { getComponentIssuesUrl } from '../../../helpers/urls';
@@ -39,6 +40,7 @@ import {
} from '../../../types/clean-code-taxonomy';
import { MetricKey, MetricType } from '../../../types/metrics';
import { Component, MeasureEnhanced } from '../../../types/types';
+import { OverviewDisabledLinkTooltip } from '../components/OverviewDisabledLinkTooltip';
import { softwareQualityToMeasure } from '../utils';
import SoftwareImpactMeasureBreakdownCard from './SoftwareImpactMeasureBreakdownCard';
import SoftwareImpactMeasureRating from './SoftwareImpactMeasureRating';
@@ -60,6 +62,8 @@ export function SoftwareImpactMeasureCard(props: Readonly<SoftwareImpactBreakdow
const measureRaw = measures.find((m) => m.metric.key === metricKey);
const measure = JSON.parse(measureRaw?.value ?? 'null') as SoftwareImpactMeasureData;
+ const renderDisabled = !measure || component.needIssueSync;
+
// Find rating measure
const ratingMeasure = measures.find((m) => m.metric.key === ratingMetricKey);
@@ -85,28 +89,31 @@ export function SoftwareImpactMeasureCard(props: Readonly<SoftwareImpactBreakdow
<div className="sw-flex sw-flex-col sw-gap-3">
<div
className={classNames('sw-flex sw-gap-1 sw-items-end', {
- 'sw-opacity-60': !measure,
+ 'sw-opacity-60': renderDisabled,
})}
>
{measure ? (
- <NakedLink
- data-testid={`overview__software-impact-${softwareQuality}`}
- aria-label={intl.formatMessage(
- {
- id: `overview.measures.software_impact.see_list_of_x_open_issues`,
- },
- {
- count: measure.total,
- softwareQuality: intl.formatMessage({
- id: `software_quality.${softwareQuality}`,
- }),
- },
- )}
- className="sw-text-xl"
- to={totalLinkHref}
- >
- {formatMeasure(measure.total, MetricType.ShortInteger)}
- </NakedLink>
+ <Tooltip overlay={component.needIssueSync ? <OverviewDisabledLinkTooltip /> : null}>
+ <NakedLink
+ data-testid={`overview__software-impact-${softwareQuality}`}
+ aria-label={intl.formatMessage(
+ {
+ id: `overview.measures.software_impact.see_list_of_x_open_issues`,
+ },
+ {
+ count: measure.total,
+ softwareQuality: intl.formatMessage({
+ id: `software_quality.${softwareQuality}`,
+ }),
+ },
+ )}
+ className="sw-text-xl"
+ to={totalLinkHref}
+ disabled={component.needIssueSync}
+ >
+ {formatMeasure(measure.total, MetricType.ShortInteger)}
+ </NakedLink>
+ </Tooltip>
) : (
<StyledDash className="sw-self-center sw-font-bold" name="-" />
)}
diff --git a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx
index a956a8b75e3..e8710eaca52 100644
--- a/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/branches/__tests__/BranchOverview-it.tsx
@@ -348,6 +348,41 @@ describe('project overview', () => {
false,
]);
});
+
+ it('should disable software impact measure card links during reindexing', async () => {
+ const { user, ui } = getPageObjects();
+ renderBranchOverview({
+ component: mockComponent({
+ breadcrumbs: [mockComponent({ key: 'foo' })],
+ key: 'foo',
+ needIssueSync: true,
+ }),
+ });
+
+ await user.click(await ui.overallCodeButton.find());
+
+ expect(await ui.softwareImpactMeasureCard(SoftwareQuality.Security).find()).toBeInTheDocument();
+
+ ui.expectSoftwareImpactMeasureCard(
+ SoftwareQuality.Security,
+ 'B',
+ {
+ total: 1,
+ [SoftwareImpactSeverity.High]: 0,
+ [SoftwareImpactSeverity.Medium]: 1,
+ [SoftwareImpactSeverity.Low]: 0,
+ },
+ [false, true, false],
+ );
+
+ await expect(
+ byRole('link', {
+ name: `overview.measures.software_impact.see_list_of_x_open_issues.${1}.software_quality.${
+ SoftwareQuality.Security
+ }`,
+ }).get(),
+ ).toHaveATooltipWithContent('indexation.in_progress');
+ });
});
describe('application overview', () => {
diff --git a/server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx b/server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx
index de80ee18c20..68c6174487b 100644
--- a/server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx
+++ b/server/sonar-web/src/main/js/apps/overview/components/MeasuresCard.tsx
@@ -18,7 +18,7 @@
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
import styled from '@emotion/styled';
-import { Badge, Card, ContentLink, themeBorder, themeColor } from 'design-system';
+import { Badge, Card, ContentLink, Tooltip, themeBorder, themeColor } from 'design-system';
import * as React from 'react';
import { To } from 'react-router-dom';
import { translate, translateWithParameters } from '../../../helpers/l10n';
@@ -32,12 +32,14 @@ export interface MeasuresCardProps {
label: string;
failed?: boolean;
icon?: React.ReactElement;
+ disabled?: boolean;
+ tooltip?: React.ReactNode | null;
}
export default function MeasuresCard(
props: React.PropsWithChildren<MeasuresCardProps & React.HTMLAttributes<HTMLDivElement>>,
) {
- const { failed, children, metric, icon, value, url, label, ...rest } = props;
+ 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}>
@@ -49,17 +51,20 @@ export default function MeasuresCard(
)}
<div className="sw-flex sw-items-center sw-mt-1 sw-justify-between sw-font-semibold">
{value ? (
- <ContentLink
- aria-label={translateWithParameters(
- 'overview.see_more_details_on_x_of_y',
- value,
- localizeMetric(metric),
- )}
- className="it__overview-measures-value sw-text-lg"
- to={url}
- >
- {value}
- </ContentLink>
+ <Tooltip overlay={tooltip}>
+ <ContentLink
+ aria-label={translateWithParameters(
+ 'overview.see_more_details_on_x_of_y',
+ value,
+ localizeMetric(metric),
+ )}
+ className="it__overview-measures-value sw-text-lg"
+ to={url}
+ disabled={disabled}
+ >
+ {value}
+ </ContentLink>
+ </Tooltip>
) : (
<ColorBold> — </ColorBold>
)}