@@ -24,6 +24,7 @@ import { RULE_TYPES } from '../../../helpers/constants'; | |||
import { parseDate } from '../../../helpers/dates'; | |||
import { mockCurrentUser, mockLoggedInUser } from '../../../helpers/testMocks'; | |||
import { dateInputEvent, renderAppRoutes } from '../../../helpers/testReactTestingUtils'; | |||
import { CleanCodeAttributeCategory, SoftwareQuality } from '../../../types/clean-code-taxonomy'; | |||
import { CurrentUser } from '../../../types/users'; | |||
import routes from '../routes'; | |||
import { getPageObjects } from '../utils-tests'; | |||
@@ -44,6 +45,14 @@ describe('Rules app list', () => { | |||
.allRulesName() | |||
.forEach((name) => expect(ui.ruleListItemLink(name).get()).toBeInTheDocument()); | |||
// Render clean code attributes. | |||
expect( | |||
ui.ruleCleanCodeAttributeCategory(CleanCodeAttributeCategory.Adaptable).getAll().length | |||
).toBeGreaterThan(1); | |||
expect(ui.ruleSoftwareQuality(SoftwareQuality.Maintainability).getAll().length).toBeGreaterThan( | |||
1 | |||
); | |||
// Renders type facets | |||
RULE_TYPES.map((type) => `issue.type.${type}`).forEach((name) => | |||
expect(ui.facetItem(name).get()).toBeInTheDocument() |
@@ -24,8 +24,9 @@ import Link from '../../../components/common/Link'; | |||
import { Button } from '../../../components/controls/buttons'; | |||
import ConfirmButton from '../../../components/controls/ConfirmButton'; | |||
import Tooltip from '../../../components/controls/Tooltip'; | |||
import IssueTypeIcon from '../../../components/icons/IssueTypeIcon'; | |||
import SeverityIcon from '../../../components/icons/SeverityIcon'; | |||
import { CleanCodeAttributePill } from '../../../components/shared/CleanCodeAttributePill'; | |||
import SoftwareImpactPill from '../../../components/shared/SoftwareImpactPill'; | |||
import TagsList from '../../../components/tags/TagsList'; | |||
import { translate, translateWithParameters } from '../../../helpers/l10n'; | |||
import { getRuleUrl } from '../../../helpers/urls'; | |||
@@ -231,6 +232,13 @@ export default class RuleListItem extends React.PureComponent<Props> { | |||
<td className="coding-rule-table-meta-cell"> | |||
<div className="display-flex-center coding-rule-meta"> | |||
{rule.cleanCodeAttributeCategory !== undefined && ( | |||
<CleanCodeAttributePill | |||
className="spacer-left" | |||
cleanCodeAttributeCategory={rule.cleanCodeAttributeCategory} | |||
type="rule" | |||
/> | |||
)} | |||
{rule.status !== 'READY' && ( | |||
<span className="spacer-left badge badge-error"> | |||
{translate('rules.status', rule.status)} | |||
@@ -239,14 +247,16 @@ export default class RuleListItem extends React.PureComponent<Props> { | |||
<span className="display-inline-flex-center spacer-left note"> | |||
{rule.langName} | |||
</span> | |||
<Tooltip overlay={translate('coding_rules.type.tooltip', rule.type)}> | |||
<span className="display-inline-flex-center spacer-left note"> | |||
<IssueTypeIcon query={rule.type} /> | |||
<span className="little-spacer-left text-middle"> | |||
{translate('issue.type', rule.type)} | |||
</span> | |||
</span> | |||
</Tooltip> | |||
{rule.impacts !== undefined && | |||
rule.impacts.map(({ severity, softwareQuality }) => ( | |||
<SoftwareImpactPill | |||
className="spacer-left" | |||
key={softwareQuality} | |||
severity={severity} | |||
quality={softwareQuality} | |||
type="rule" | |||
/> | |||
))} | |||
{allTags.length > 0 && ( | |||
<TagsList | |||
allowUpdate={false} |
@@ -21,6 +21,11 @@ import { waitFor } from '@testing-library/react'; | |||
import userEvent from '@testing-library/user-event'; | |||
import { Profile } from '../../api/quality-profiles'; | |||
import { byLabelText, byPlaceholderText, byRole, byText } from '../../helpers/testSelector'; | |||
import { | |||
CleanCodeAttribute, | |||
CleanCodeAttributeCategory, | |||
SoftwareQuality, | |||
} from '../../types/clean-code-taxonomy'; | |||
const selectors = { | |||
loading: byLabelText('loading'), | |||
@@ -92,6 +97,11 @@ const selectors = { | |||
saveButton: byRole('button', { name: 'save' }), | |||
cancelButton: byRole('button', { name: 'cancel' }), | |||
removeButton: byRole('button', { name: 'remove' }), | |||
ruleCleanCodeAttributeCategory: (category: CleanCodeAttributeCategory) => | |||
byText(`rule.clean_code_attribute_category.${category}.title_short`), | |||
ruleCleanCodeAttribute: (attribute: CleanCodeAttribute) => | |||
byText(new RegExp(`rule\\.clean_code_attribute\\.${attribute}$`)), | |||
ruleSoftwareQuality: (quality: SoftwareQuality) => byText(`issue.software_quality.${quality}`), | |||
// Rule tags | |||
tagsDropdown: byRole('button', { name: /tags_list_x/ }), |
@@ -52,7 +52,7 @@ it('renders correctly', async () => { | |||
// CCT attribute | |||
const cctBadge = byText( | |||
`issue.clean_code_attribute_category.${issue.cleanCodeAttributeCategory}.issue` | |||
`issue.clean_code_attribute_category.${issue.cleanCodeAttributeCategory}.title_short` | |||
).get(); | |||
expect(cctBadge).toBeInTheDocument(); | |||
await expect(cctBadge).toHaveATooltipWithContent( |
@@ -26,23 +26,37 @@ import DocumentationTooltip from '../common/DocumentationTooltip'; | |||
export interface Props { | |||
className?: string; | |||
type?: 'issue' | 'rule'; | |||
cleanCodeAttributeCategory: CleanCodeAttributeCategory; | |||
cleanCodeAttribute?: CleanCodeAttribute; | |||
} | |||
export function CleanCodeAttributePill(props: Props) { | |||
const { className, cleanCodeAttributeCategory, cleanCodeAttribute } = props; | |||
const translationKey = cleanCodeAttribute | |||
? `issue.clean_code_attribute.${cleanCodeAttribute}` | |||
: `issue.clean_code_attribute_category.${cleanCodeAttributeCategory}`; | |||
const { className, cleanCodeAttributeCategory, cleanCodeAttribute, type = 'issue' } = props; | |||
const showAdvice = type === 'issue'; | |||
return ( | |||
<DocumentationTooltip | |||
content={ | |||
<> | |||
<p className="sw-mb-4">{translate(translationKey, 'title')}</p> | |||
<p>{translate(translationKey, 'advice')}</p> | |||
<p className="sw-mb-4"> | |||
{translate( | |||
type, | |||
cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category', | |||
cleanCodeAttribute ?? cleanCodeAttributeCategory, | |||
'title' | |||
)} | |||
</p> | |||
{showAdvice && ( | |||
<p> | |||
{translate( | |||
type, | |||
cleanCodeAttribute ? 'clean_code_attribute' : 'clean_code_attribute_category', | |||
cleanCodeAttribute ?? cleanCodeAttributeCategory, | |||
'advice' | |||
)} | |||
</p> | |||
)} | |||
</> | |||
} | |||
links={[ | |||
@@ -54,10 +68,15 @@ export function CleanCodeAttributePill(props: Props) { | |||
> | |||
<Pill variant="neutral" data-guiding-id="issue-1" className={className}> | |||
<span className={classNames({ 'sw-font-semibold': !!cleanCodeAttribute })}> | |||
{translate('issue.clean_code_attribute_category', cleanCodeAttributeCategory, 'issue')} | |||
{translate( | |||
type, | |||
'clean_code_attribute_category', | |||
cleanCodeAttributeCategory, | |||
'title_short' | |||
)} | |||
</span> | |||
{cleanCodeAttribute && ( | |||
<span> | {translate('issue.clean_code_attribute', cleanCodeAttribute)}</span> | |||
<span> | {translate(type, 'clean_code_attribute', cleanCodeAttribute)}</span> | |||
)} | |||
</Pill> | |||
</DocumentationTooltip> |
@@ -29,11 +29,12 @@ import SoftwareImpactSeverityIcon from '../icons/SoftwareImpactSeverityIcon'; | |||
export interface Props { | |||
className?: string; | |||
severity: SoftwareImpactSeverity; | |||
type?: 'issue' | 'rule'; | |||
quality: SoftwareQuality; | |||
} | |||
export default function SoftwareImpactPill(props: Props) { | |||
const { className, severity, quality } = props; | |||
const { className, severity, quality, type = 'issue' } = props; | |||
const variant = { | |||
[SoftwareImpactSeverity.High]: 'danger', | |||
@@ -45,8 +46,8 @@ export default function SoftwareImpactPill(props: Props) { | |||
<DocumentationTooltip | |||
content={ | |||
<FormattedMessage | |||
id="issue.impact.severity.tooltip" | |||
defaultMessage={translate('issue.impact.severity.tooltip')} | |||
id={`${type}.impact.severity.tooltip`} | |||
defaultMessage={translate(`${type}.impact.severity.tooltip`)} | |||
values={{ | |||
severity: translate('severity', severity).toLowerCase(), | |||
quality: translate('issue.software_quality', quality).toLowerCase(), |
@@ -986,19 +986,19 @@ issue.impact.severity.tooltip=This issue has a {severity} impact on the {quality | |||
issue.clean_code_attribute_category.CONSISTENT=Consistency | |||
issue.clean_code_attribute_category.CONSISTENT.title=This is a consistency issue. | |||
issue.clean_code_attribute_category.CONSISTENT.advice=To be consistent, the code needs to be written in a uniform and conventional way. | |||
issue.clean_code_attribute_category.CONSISTENT.issue=Consistency issue | |||
issue.clean_code_attribute_category.CONSISTENT.title_short=Consistency issue | |||
issue.clean_code_attribute_category.INTENTIONAL=Intentionality | |||
issue.clean_code_attribute_category.INTENTIONAL.title=This is an intentionality issue. | |||
issue.clean_code_attribute_category.INTENTIONAL.advice=To be intentional, the code content needs to be precise and purposeful. | |||
issue.clean_code_attribute_category.INTENTIONAL.issue=Intentionality issue | |||
issue.clean_code_attribute_category.INTENTIONAL.title_short=Intentionality issue | |||
issue.clean_code_attribute_category.ADAPTABLE=Adaptability | |||
issue.clean_code_attribute_category.ADAPTABLE.title=This is an adaptability issue. | |||
issue.clean_code_attribute_category.ADAPTABLE.advice=To be adaptable, code needs to be structured to be easy to evolve with confidence. | |||
issue.clean_code_attribute_category.ADAPTABLE.issue=Adaptability issue | |||
issue.clean_code_attribute_category.ADAPTABLE.title_short=Adaptability issue | |||
issue.clean_code_attribute_category.RESPONSIBLE=Responsibility | |||
issue.clean_code_attribute_category.RESPONSIBLE.title=This is a responsibility issue. | |||
issue.clean_code_attribute_category.RESPONSIBLE.advice=To be responsible, the code must take into account its ethical obligations on data and potential impact of societal norms. | |||
issue.clean_code_attribute_category.RESPONSIBLE.issue=Responsibility issue | |||
issue.clean_code_attribute_category.RESPONSIBLE.title_short=Responsibility issue | |||
issue.clean_code_attribute=Clean Code Attribute | |||
issue.clean_code_attribute.CLEAR=Not clear | |||
@@ -2365,6 +2365,53 @@ coding_rules.more_info.resources.title=Resources | |||
coding_rules.more_info.notification_message=We've added new information about Clean Code principles below to help you improve your code quality and security. Take a moment to read through them. | |||
coding_rules.more_info.scroll_message=Scroll down to Code Quality principles | |||
rule.impact.severity.tooltip=Issues found for this rule will have a {severity} impact on the {quality} of your software. | |||
rule.clean_code_attribute_category.CONSISTENT=Consistency | |||
rule.clean_code_attribute_category.CONSISTENT.title=This is a consistency rule. | |||
rule.clean_code_attribute_category.CONSISTENT.title_short=Consistency rule | |||
rule.clean_code_attribute_category.INTENTIONAL=Intentionality | |||
rule.clean_code_attribute_category.INTENTIONAL.title=This is an intentionality rule. | |||
rule.clean_code_attribute_category.INTENTIONAL.title_short=Intentionality rule | |||
rule.clean_code_attribute_category.ADAPTABLE=Adaptability | |||
rule.clean_code_attribute_category.ADAPTABLE.title=This is an adaptability rule. | |||
rule.clean_code_attribute_category.ADAPTABLE.title_short=Adaptability rule | |||
rule.clean_code_attribute_category.RESPONSIBLE=Responsibility | |||
rule.clean_code_attribute_category.RESPONSIBLE.title=This is a responsibility rule. | |||
rule.clean_code_attribute_category.RESPONSIBLE.title_short=Responsibility rule | |||
rule.clean_code_attribute.CLEAR=Clear | |||
rule.clean_code_attribute.CLEAR.title=This is an intentionality rule, the code is not clear enough. | |||
rule.clean_code_attribute.COMPLETE=Complete | |||
rule.clean_code_attribute.COMPLETE.title=This is a intentionality rule, the code is not complete enough. | |||
rule.clean_code_attribute.CONVENTIONAL=Conventional | |||
rule.clean_code_attribute.CONVENTIONAL.title=This is a consistency rule, the code is not conventional enough. | |||
rule.clean_code_attribute.DISTINCT=Distinct | |||
rule.clean_code_attribute.DISTINCT.title=This is an adaptability rule, the code is not distinct enough. | |||
rule.clean_code_attribute.EFFICIENT=Efficient | |||
rule.clean_code_attribute.EFFICIENT.title=This is an intentionality rule, the code is not efficient enough. | |||
rule.clean_code_attribute.FOCUSED=Focused | |||
rule.clean_code_attribute.FOCUSED.title=This is an adaptability rule, the code is not focused enough. | |||
rule.clean_code_attribute.FORMATTED=Formatted | |||
rule.clean_code_attribute.FORMATTED.title=This is a consistency rule, the code is not formatted enough. | |||
rule.clean_code_attribute.IDENTIFIABLE=Identifiable | |||
rule.clean_code_attribute.IDENTIFIABLE.title=This is a consistency rule, the code is not identifiable enough. | |||
rule.clean_code_attribute.LAWFUL=Lawful | |||
rule.clean_code_attribute.LAWFUL.title=This is a responsibility rule, the code is not lawful enough. | |||
rule.clean_code_attribute.LOGICAL=Logical | |||
rule.clean_code_attribute.LOGICAL.title=This is an intentionality rule, the code is not logical enough. | |||
rule.clean_code_attribute.MODULAR=Modular | |||
rule.clean_code_attribute.MODULAR.title=This is an adaptability rule, the code is not modular enough. | |||
rule.clean_code_attribute.RESPECTFUL=Respectful | |||
rule.clean_code_attribute.RESPECTFUL.title=This is a responsibility rule, the code is not respectful enough. | |||
rule.clean_code_attribute.TESTED=Tested | |||
rule.clean_code_attribute.TESTED.title=This is an adaptability rule, the code is not tested enough. | |||
rule.clean_code_attribute.TRUSTWORTHY=Trustworthy | |||
rule.clean_code_attribute.TRUSTWORTHY.title=This is a responsibility rule, the code is not trustworthy enough. | |||
#------------------------------------------------------------------------------ | |||
# | |||
# EMAIL CONFIGURATION |