};
interface PillProps {
+ ['aria-label']?: string;
children: ReactNode;
className?: string;
- title?: string;
variant: PillVariant;
}
-export function Pill({ className, children, title, variant }: PillProps) {
- const commonProps = {
- 'aria-label': title ?? children?.toString(),
- className,
- role: 'status',
- title,
- };
+export function Pill({ children, variant, ...rest }: PillProps) {
return (
- <StyledPill color={variantThemeColors[variant]} {...commonProps}>
+ <StyledPill color={variantThemeColors[variant]} {...rest}>
{children}
</StyledPill>
);
it('should render correctly', () => {
render(<Pill variant="neutral">23</Pill>);
- expect(screen.getByRole('status')).toBeInTheDocument();
- expect(screen.getByRole('status')).toHaveAttribute('aria-label', '23');
-});
-
-it('should accept overriding label', () => {
- render(
- <Pill title="23 foo in bucket" variant="danger">
- 23
- </Pill>
- );
- expect(screen.getByRole('status')).toHaveAttribute('aria-label', '23 foo in bucket');
+ expect(screen.getByText('23')).toBeInTheDocument();
});
SoftwareImpactSeverityMediumIcon,
} from 'design-system';
import * as React from 'react';
+import { translate } from '../../helpers/l10n';
import { SoftwareImpactSeverity } from '../../types/issues';
import { Dict } from '../../types/types';
import { IconProps } from './Icon';
}
const DesiredIcon = severityIcons[severity];
- return <DesiredIcon {...iconProps} />;
+ return <DesiredIcon {...iconProps} aria-label={translate('severity', severity)} />;
}
field: 'type' | 'severity';
}
+const FILTERS_LIST = {
+ type: ['issue.clean_code_attributes', 'issue.software_qualities'],
+ severity: ['issue.software_qualities', 'issue.severity.new'],
+};
+
export function DeprecatedFieldTooltip({ field, docUrl }: DeprecatedTooltipProps) {
return (
<>
<p className="sw-mb-4">{translate('issue', field, 'deprecation.title')}</p>
<p>{translate('issue', field, 'deprecation.filter_by')}</p>
<ul className="sw-list-disc sw-ml-6">
- <li>{translate('issue.clean_code_attributes')}</li>
- <li>{translate('issue.software_qualities')}</li>
+ {FILTERS_LIST[field].map((key) => (
+ <li key={key}>{translate(key)}</li>
+ ))}
</ul>
<hr className="sw-w-full sw-mx-0 sw-my-4" />
<FormattedMessage
</li>
<li className="sw-flex sw-gap-3">
- {issue.impacts.map(({ severity, softwareQuality }, index) => (
+ {issue.impacts.map(({ severity, softwareQuality }) => (
<SoftwareImpactPill
- key={index}
- cleanCodeAttributeCategory={issue.cleanCodeAttributeCategory}
+ key={softwareQuality}
severity={severity}
quality={softwareQuality}
/>
}
export default function IssueSeverity({ issue }: Props) {
- const docUrl = useDocUrl('/');
+ const docUrl = useDocUrl('/user-guide/clean-code');
return (
- <Tooltip overlay={<DeprecatedFieldTooltip field="type" docUrl={docUrl} />}>
+ <Tooltip
+ mouseLeaveDelay={0.25}
+ overlay={<DeprecatedFieldTooltip field="severity" docUrl={docUrl} />}
+ >
<DisabledText className="sw-flex sw-items-center sw-gap-1 sw-cursor-not-allowed">
<IssueSeverityIcon
fill="iconSeverityDisabled"
<div className="sw-flex sw-items-end">
<div className="sw-w-full sw-flex sw-flex-col">
<CleanCodeAttributePill
- className="sw-mb-1"
+ className="sw-mb-2"
cleanCodeAttributeCategory={issue.cleanCodeAttributeCategory}
/>
<div className="sw-w-fit">
}
export default function IssueType({ issue }: Props) {
- const docUrl = useDocUrl('/');
+ const docUrl = useDocUrl('/user-guide/clean-code');
return (
- <Tooltip overlay={<DeprecatedFieldTooltip field="type" docUrl={docUrl} />}>
+ <Tooltip
+ mouseLeaveDelay={0.25}
+ overlay={<DeprecatedFieldTooltip field="type" docUrl={docUrl} />}
+ >
<DisabledText className="sw-flex sw-items-center sw-gap-1 sw-cursor-not-allowed">
<IssueTypeIcon fill="iconTypeDisabled" type={issue.type} aria-hidden />
{translate('issue.type', issue.type)}
>
<div className="sw-flex sw-w-full sw-px-2 sw-gap-4">
{hasCheckbox && (
- <span className="sw-mt-6 sw-self-start">
+ <span className="sw-mt-7 sw-self-start">
<Checkbox
checked={checked ?? false}
onCheck={this.handleCheck}
</span>
)}
- <div className="sw-flex sw-flex-col sw-grow sw-gap-2">
+ <div className="sw-flex sw-flex-col sw-grow sw-gap-4">
<IssueTitleBar
currentPopup={currentPopup}
branchLike={branchLike}
export function CleanCodeAttributePill(props: Props) {
const { className, cleanCodeAttributeCategory } = props;
- const docUrl = useDocUrl('/');
+ const docUrl = useDocUrl('/user-guide/clean-code');
return (
<Tooltip
+ mouseLeaveDelay={0.25}
overlay={
<>
<p className="sw-mb-4">
</>
}
>
- <span className="sw-w-fit">
- <Pill variant="neutral" className={classNames('sw-mr-2', className)}>
- {translate('issue.clean_code_attribute_category', cleanCodeAttributeCategory, 'issue')}
- </Pill>
- </span>
+ <Pill variant="neutral" className={classNames('sw-mr-2', className)}>
+ {translate('issue.clean_code_attribute_category', cleanCodeAttributeCategory, 'issue')}
+ </Pill>
</Tooltip>
);
}
import { FormattedMessage } from 'react-intl';
import { useDocUrl } from '../../helpers/docs';
import { translate } from '../../helpers/l10n';
-import {
- CleanCodeAttributeCategory,
- SoftwareImpactSeverity,
- SoftwareQuality,
-} from '../../types/issues';
+import { SoftwareImpactSeverity, SoftwareQuality } from '../../types/issues';
import Tooltip from '../controls/Tooltip';
import SoftwareImpactSeverityIcon from '../icons/SoftwareImpactSeverityIcon';
export interface Props {
className?: string;
- cleanCodeAttributeCategory: CleanCodeAttributeCategory;
severity: SoftwareImpactSeverity;
quality: SoftwareQuality;
}
export default function SoftwareImpactPill(props: Props) {
- const { cleanCodeAttributeCategory, className, severity, quality } = props;
+ const { className, severity, quality } = props;
- const docUrl = useDocUrl('/');
+ const docUrl = useDocUrl('/user-guide/clean-code');
const variant = {
[SoftwareImpactSeverity.High]: 'danger',
return (
<div>
<Tooltip
+ mouseLeaveDelay={0.25}
overlay={
<>
- <p className="sw-mb-4">
- {translate(
- 'issue.clean_code_attribute_category',
- cleanCodeAttributeCategory,
- 'title'
- )}
- </p>
- <p>
- <FormattedMessage
- id="issue.impact.severity.tooltip"
- defaultMessage={translate('issue.impact.severity.tooltip')}
- values={{
- severity: translate('severity', severity).toLowerCase(),
- quality: translate('issue.software_quality', quality).toLowerCase(),
- }}
- />
- </p>
+ <FormattedMessage
+ id="issue.impact.severity.tooltip"
+ defaultMessage={translate('issue.impact.severity.tooltip')}
+ values={{
+ severity: translate('severity', severity).toLowerCase(),
+ quality: translate('issue.software_quality', quality).toLowerCase(),
+ }}
+ />
<hr className="sw-w-full sw-mx-0 sw-my-4" />
<FormattedMessage
defaultMessage={translate('learn_more_x')}
</>
}
>
- <span>
- <Pill
- className={classNames('sw-flex sw-gap-1 sw-items-center', className)}
- variant={variant}
- >
- {translate('issue.software_quality', quality)}
- <SoftwareImpactSeverityIcon severity={severity} />
- </Pill>
- </span>
+ <Pill
+ className={classNames('sw-flex sw-gap-1 sw-items-center', className)}
+ variant={variant}
+ >
+ {translate('issue.software_quality', quality)}
+ <SoftwareImpactSeverityIcon severity={severity} />
+ </Pill>
</Tooltip>
</div>
);
issue.severity.deprecation.title=Severities are now directly tied to the software quality impacted. This old severity is deprecated and can no longer be modified.
issue.severity.deprecation.filter_by=You can now filter issues by:
issue.severity.deprecation.documentation=Documentation
+issue.severity.new=The new severities
issue.software_qualities=Software qualities
issue.software_quality.SECURITY=Security
projects_role.admin=Administer
projects_role.admin.desc=Access project settings and perform administration tasks (for private projects, users also need the "Browse" permission)
projects_role.issueadmin=Administer Issues
-projects_role.issueadmin.desc=Change the type and severity of issues, resolve issues as being "fixed", "won't fix" or "false-positive" (for private projects, users also need the "Browse" permission).
+projects_role.issueadmin.desc=Resolve issues as being "fixed", "won't fix" or "false-positive" (for private projects, users also need the "Browse" permission).
projects_role.securityhotspotadmin=Administer Security Hotspots
projects_role.securityhotspotadmin.desc=Resolve a Security Hotspot as reviewed (fixed or safe), reset it as to review (for private projects, users also need the "Browse" permission).
projects_role.user=Browse