grey: { 50: [235, 235, 235], 100: [221, 221, 221] },
blueGrey: {
25: [252, 252, 253],
+ 35: [247, 249, 252],
50: [239, 242, 249],
100: [225, 230, 243],
200: [197, 205, 223],
// project
projectCardBackground: COLORS.white,
projectCardBorder: COLORS.blueGrey[100],
- projectLightGreyCardBorder: COLORS.grey[50],
+ projectCardInfo: COLORS.blueGrey[35],
// overview
overviewCardDefaultIcon: secondary.light,
Card,
HighImpactCircleIcon,
LightLabel,
+ NoDataIcon,
PageTitle,
SnoozeCircleIcon,
Spinner,
>
<Card className="sw-flex sw-gap-4">
<IssueMeasuresCardInner
- linkDisabled={component.needIssueSync}
+ disabled={component.needIssueSync}
className={classNames({ 'sw-w-1/2': !isNewCode, 'sw-w-full': isNewCode })}
- noDataIconClassName="sw--translate-y-3"
metric={MetricKey.accepted_issues}
value={formatMeasure(acceptedCount, MetricType.ShortInteger)}
header={intl.formatMessage({
<>
<StyledCardSeparator />
<IssueMeasuresCardInner
- linkDisabled={component.needIssueSync}
+ disabled={Boolean(component.needIssueSync) || !acceptedWithHighImpactCount}
className="sw-w-1/2"
- noDataIconClassName="sw--translate-y-3"
metric={MetricKey.high_impact_accepted_issues}
value={formatMeasure(acceptedWithHighImpactCount, MetricType.ShortInteger)}
header={intl.formatMessage({
id: 'overview.high_impact_accepted_issues',
})}
url={acceptedIssuesWithHighImpactUrl}
- icon={<HighImpactCircleIcon className="sw--translate-y-3" />}
+ icon={
+ acceptedWithHighImpactCount ? (
+ <HighImpactCircleIcon className="sw--translate-y-3" />
+ ) : (
+ <NoDataIcon className="sw--translate-y-3" width={36} height={36} />
+ )
+ }
/>
</>
)}
);
}
+ let acceptedIssuesFooter = null;
+ if (!newAcceptedIssues) {
+ acceptedIssuesFooter = (
+ <StyledInfoMessage className="sw-rounded-2 sw-text-xs sw-p-4 sw-flex sw-gap-1 sw-flex-wrap">
+ <span>{intl.formatMessage({ id: 'overview.project.no_data' })}</span>
+ <span>
+ {intl.formatMessage({
+ id: `overview.run_analysis_to_compute.${component.qualifier}`,
+ })}
+ </span>
+ </StyledInfoMessage>
+ );
+ } else {
+ acceptedIssuesFooter = (
+ <TextSubdued className="sw-body-xs">
+ {intl.formatMessage({ id: 'overview.accepted_issues.help' })}
+ </TextSubdued>
+ );
+ }
+
return (
<div className="sw-mt-6" id={getTabPanelId(MeasuresTabs.New)}>
<LightGreyCard className="sw-flex sw-rounded-2 sw-gap-4">
<IssueMeasuresCardInner
data-test="overview__measures-new_issues"
- linkDisabled={component.needIssueSync}
+ disabled={component.needIssueSync}
className="sw-w-1/2"
metric={MetricKey.new_violations}
value={formatMeasure(newIssues, MetricType.ShortInteger)}
<StyledCardSeparator />
<IssueMeasuresCardInner
data-test="overview__measures-accepted_issues"
- linkDisabled={component.needIssueSync}
+ disabled={Boolean(component.needIssueSync) || !newAcceptedIssues}
className="sw-w-1/2"
metric={MetricKey.new_accepted_issues}
value={formatMeasure(newAcceptedIssues, MetricType.ShortInteger)}
issueStatuses: IssueStatus.Accepted,
inNewCodePeriod: 'true',
})}
- footer={
- <TextSubdued className="sw-body-xs">
- {intl.formatMessage({ id: 'overview.accepted_issues.help' })}
- </TextSubdued>
- }
+ footer={acceptedIssuesFooter}
icon={
<SnoozeCircleIcon
color={
width: 1px;
background-color: ${themeColor('projectCardBorder')};
`;
+
+const StyledInfoMessage = styled.div`
+ background-color: ${themeColor('projectCardInfo')};
+`;
*/
import styled from '@emotion/styled';
import classNames from 'classnames';
-import { Badge, ContentLink, LightLabel, NoDataIcon, themeColor } from 'design-system';
+import { Badge, ContentLink, themeColor } from 'design-system';
import * as React from 'react';
import { Path } from 'react-router-dom';
import Tooltip from '../../../components/controls/Tooltip';
import { MetricKey } from '../../../types/metrics';
import { OverviewDisabledLinkTooltip } from './OverviewDisabledLinkTooltip';
-const NO_DATA_ICON_SIZE = 36;
-
interface IssueMeasuresCardInnerProps extends React.HTMLAttributes<HTMLDivElement> {
metric: MetricKey;
value?: string;
url: Path;
failed?: boolean;
icon?: React.ReactNode;
- linkDisabled?: boolean;
+ disabled?: boolean;
footer?: React.ReactNode;
- noDataIconClassName?: string;
}
export function IssueMeasuresCardInner(props: Readonly<IssueMeasuresCardInnerProps>) {
- const {
- header,
- metric,
- icon,
- value,
- url,
- failed,
- footer,
- className,
- noDataIconClassName,
- linkDisabled,
- ...rest
- } = props;
+ const { header, metric, icon, value, url, failed, footer, className, disabled, ...rest } = props;
return (
<div className={classNames('sw-flex sw-flex-col sw-gap-3', className)} {...rest}>
- <div className="sw-flex sw-flex-col sw-gap-2 sw-font-semibold">
+ <div
+ className={classNames('sw-flex sw-flex-col sw-gap-2 sw-font-semibold', {
+ 'sw-opacity-60': disabled,
+ })}
+ >
<ColorBold className="sw-flex sw-items-center sw-gap-2 sw-body-sm-highlight">
{header}
</ColorBold>
<div className="sw-flex sw-justify-between sw-items-center sw-h-9">
<div className="sw-h-fit">
- {value ? (
- <Tooltip
- classNameSpace={linkDisabled ? 'tooltip' : 'sw-hidden'}
- overlay={<OverviewDisabledLinkTooltip />}
+ <Tooltip
+ classNameSpace={disabled ? 'tooltip' : 'sw-hidden'}
+ overlay={value && <OverviewDisabledLinkTooltip />}
+ >
+ <ContentLink
+ disabled={disabled || !value}
+ aria-label={
+ value
+ ? translateWithParameters(
+ 'overview.see_more_details_on_x_of_y',
+ value,
+ localizeMetric(metric),
+ )
+ : translate('no_data')
+ }
+ className="it__overview-measures-value sw-w-fit sw-text-lg"
+ to={url}
>
- <ContentLink
- disabled={linkDisabled}
- aria-label={translateWithParameters(
- 'overview.see_more_details_on_x_of_y',
- value,
- localizeMetric(metric),
- )}
- className="it__overview-measures-value sw-w-fit sw-text-lg"
- to={url}
- >
- {value}
- </ContentLink>
- </Tooltip>
- ) : (
- <Tooltip overlay={translate('no_data')}>
- <LightLabel aria-label={translate('no_data')}> — </LightLabel>
- </Tooltip>
- )}
+ {value ? value : '-'}
+ </ContentLink>
+ </Tooltip>
</div>
- {value ? (
- icon
- ) : (
- <NoDataIcon
- className={noDataIconClassName}
- width={NO_DATA_ICON_SIZE}
- height={NO_DATA_ICON_SIZE}
- />
- )}
+ {icon}
</div>
</div>
{footer}
data-test={`overview__measures-${MetricKey.new_accepted_issues}`}
metric={MetricKey.new_accepted_issues}
value={formatMeasure(acceptedCount, MetricType.ShortInteger)}
- linkDisabled={component.needIssueSync}
+ disabled={component.needIssueSync}
url={acceptedUrl}
icon={
- <SnoozeCircleIcon
- color={acceptedCount === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'}
- />
+ acceptedCount && (
+ <SnoozeCircleIcon
+ color={acceptedCount === '0' ? 'overviewCardDefaultIcon' : 'overviewCardWarningIcon'}
+ />
+ )
}
footer={
<TextSubdued className="sw-body-xs">
data-test={`overview__measures-${MetricKey.pull_request_fixed_issues}`}
metric={MetricKey.pull_request_fixed_issues}
value={formatMeasure(fixedCount, MetricType.ShortInteger)}
- linkDisabled={component.needIssueSync}
+ disabled={component.needIssueSync}
url={fixedUrl}
- icon={fixedCount !== '0' && <TrendDownCircleIcon />}
+ icon={fixedCount && fixedCount !== '0' && <TrendDownCircleIcon />}
footer={
<TextSubdued className="sw-body-xs">
{intl.formatMessage({ id: 'overview.pull_request.fixed_issues.help' })}