diff options
author | stanislavh <stanislav.honcharov@sonarsource.com> | 2024-12-03 14:00:53 +0100 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-12-04 20:03:23 +0000 |
commit | 8b42a96a0d85de0a88667c0881ba3df7a9dab3c0 (patch) | |
tree | 1500e29891eeb3a6ebd2a2cdbb6038f429a6e9fd | |
parent | 79b3fc224ffa57b1e0be55600713c577d376ba5f (diff) | |
download | sonarqube-8b42a96a0d85de0a88667c0881ba3df7a9dab3c0.tar.gz sonarqube-8b42a96a0d85de0a88667c0881ba3df7a9dab3c0.zip |
SONAR-23666 Improve accessibility by informing the user of link destination
13 files changed, 123 insertions, 55 deletions
diff --git a/server/sonar-web/__mocks__/react-intl.tsx b/server/sonar-web/__mocks__/react-intl.tsx index f68d0c36c3f..d3c6366be5d 100644 --- a/server/sonar-web/__mocks__/react-intl.tsx +++ b/server/sonar-web/__mocks__/react-intl.tsx @@ -30,7 +30,7 @@ module.exports = { {id} {Object.entries(values).map(([key, value]) => ( <React.Fragment key={key}> - {typeof value === 'function' ? value() : value} + {typeof value === 'function' ? value(`${id}_${key}`) : value} </React.Fragment> ))} </> @@ -45,7 +45,7 @@ module.exports = { values, }: { id: string; - values?: { [x: string]: React.ReactNode | (() => React.ReactNode) }; + values?: { [x: string]: React.ReactNode | ((text: string) => React.ReactNode) }; }) => { return ( <> @@ -53,7 +53,7 @@ module.exports = { {values !== undefined && Object.entries(values).map(([key, value]) => ( <React.Fragment key={key}> - {typeof value === 'function' ? value() : value} + {typeof value === 'function' ? value(`${id}_${key}`) : value} </React.Fragment> ))} </> diff --git a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx index 5e3460e49d9..0a677474771 100644 --- a/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx +++ b/server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx @@ -18,7 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Title } from '~design-system'; +import { Heading, LinkHighlight } from '@sonarsource/echoes-react'; +import { useIntl } from 'react-intl'; import DocumentationLink from '../../../components/common/DocumentationLink'; import { DocLink } from '../../../helpers/doc-links'; import { translate } from '../../../helpers/l10n'; @@ -30,15 +31,28 @@ interface Props { } export default function Header(props: Readonly<Props>) { + const intl = useIntl(); return ( <header className="sw-mb-12 sw-flex sw-justify-between"> <div className="sw-flex-1"> - <Title className="sw-mb-4">{translate('background_tasks.page')}</Title> + <Heading as="h2" className="sw-mb-4"> + {translate('background_tasks.page')} + </Heading> <p className="sw-max-w-3/4"> - {translate('background_tasks.page.description')} - <DocumentationLink className="sw-ml-2" to={DocLink.BackgroundTasks}> - {translate('learn_more')} - </DocumentationLink> + {intl.formatMessage( + { id: 'background_tasks.page.description' }, + { + link: (text) => ( + <DocumentationLink + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to={DocLink.BackgroundTasks} + > + {text} + </DocumentationLink> + ), + }, + )} </p> </div> {!props.component && ( diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx index c78f88b41c6..b760ff90556 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx @@ -68,8 +68,8 @@ export default function ListHeader({ canCreate }: Readonly<Props>) { title={intl.formatMessage({ id: 'quality_gates.help.title' })} description={intl.formatMessage({ id: 'quality_gates.help.desc' })} footer={ - <DocumentationLink standalone to={DocLink.QualityGates}> - {intl.formatMessage({ id: 'learn_more' })} + <DocumentationLink shouldOpenInNewTab standalone to={DocLink.QualityGates}> + {intl.formatMessage({ id: 'quality_gates.help.link' })} </DocumentationLink> } > diff --git a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx index 5d89c56814c..aa29b7e493d 100644 --- a/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx +++ b/server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx @@ -18,14 +18,20 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Button, ButtonGroup, ButtonVariety, Heading, Link } from '@sonarsource/echoes-react'; +import { + Button, + ButtonGroup, + ButtonVariety, + Heading, + LinkHighlight, +} from '@sonarsource/echoes-react'; import * as React from 'react'; import { useIntl } from 'react-intl'; import { FlagMessage } from '~design-system'; import { useLocation, useRouter } from '~sonar-aligned/components/hoc/withRouter'; import { Actions } from '../../../api/quality-profiles'; +import DocumentationLink from '../../../components/common/DocumentationLink'; import { DocLink } from '../../../helpers/doc-links'; -import { useDocUrl } from '../../../helpers/docs'; import { translate } from '../../../helpers/l10n'; import { Profile } from '../types'; import { getProfilePath } from '../utils'; @@ -44,7 +50,6 @@ export default function PageHeader(props: Readonly<Props>) { const intl = useIntl(); const location = useLocation(); const router = useRouter(); - const docUrl = useDocUrl(DocLink.InstanceAdminQualityProfiles); const [modal, setModal] = React.useState<'' | 'createProfile' | 'restoreProfile'>(''); @@ -67,11 +72,20 @@ export default function PageHeader(props: Readonly<Props>) { </Heading> <div className="sw-typo-default"> - {intl.formatMessage({ id: 'quality_profiles.intro' })} - - <Link className="sw-ml-2" to={docUrl}> - {intl.formatMessage({ id: 'learn_more' })} - </Link> + {intl.formatMessage( + { id: 'quality_profiles.intro' }, + { + link: (text) => ( + <DocumentationLink + shouldOpenInNewTab + to={DocLink.InstanceAdminQualityProfiles} + highlight={LinkHighlight.CurrentColor} + > + {text} + </DocumentationLink> + ), + }, + )} </div> </div> diff --git a/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx b/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx index 49525b34f73..bc7bee86eac 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx @@ -19,7 +19,8 @@ */ import styled from '@emotion/styled'; -import { LightLabel } from '~design-system'; +import { Heading, LinkHighlight, Text } from '@sonarsource/echoes-react'; +import { useIntl } from 'react-intl'; import DocumentationLink from '../../../components/common/DocumentationLink'; import { DocLink } from '../../../helpers/doc-links'; import { translate } from '../../../helpers/l10n'; @@ -28,28 +29,57 @@ import CategoryDefinitionsList from './CategoryDefinitionsList'; export function AnalysisScope(props: AdditionalCategoryComponentProps) { const { component, definitions, selectedCategory } = props; + const intl = useIntl(); return ( <> - <StyledGrid className="sw-pt-6 sw-px-6 sw-gap-2"> - <p className="sw-col-span-2"> - {translate('settings.analysis_scope.wildcards.introduction')} - </p> + <StyledGrid className="sw-pt-1 sw-px-1 sw-gap-2"> + <Heading as="h2" className="sw-col-span-2"> + {translate('property.category.exclusions')} + </Heading> - <span>*</span> - <LightLabel>{translate('settings.analysis_scope.wildcards.zero_more_char')}</LightLabel> + <Text className="sw-col-span-2 sw-mt-4 sw-mb-3"> + {intl.formatMessage( + { id: 'settings.analysis_scope.introduction' }, + { + link: (text) => ( + <DocumentationLink + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to={DocLink.AnalysisScopeWildcardPatterns} + > + {text} + </DocumentationLink> + ), + }, + )} + </Text> - <span>**</span> - <LightLabel>{translate('settings.analysis_scope.wildcards.zero_more_dir')}</LightLabel> + <Text as="p" className="sw-col-span-2"> + {intl.formatMessage( + { id: 'settings.analysis_scope.wildcards.introduction' }, + { + link: (text) => ( + <DocumentationLink + shouldOpenInNewTab + highlight={LinkHighlight.CurrentColor} + to={DocLink.AnalysisScope} + > + {text} + </DocumentationLink> + ), + }, + )} + </Text> - <span>?</span> - <LightLabel>{translate('settings.analysis_scope.wildcards.single_char')}</LightLabel> + <Text>*</Text> + <Text isSubdued>{translate('settings.analysis_scope.wildcards.zero_more_char')}</Text> - <div className="sw-col-span-2"> - <DocumentationLink to={DocLink.AnalysisScope}> - {translate('settings.analysis_scope.learn_more')} - </DocumentationLink> - </div> + <Text>**</Text> + <Text isSubdued>{translate('settings.analysis_scope.wildcards.zero_more_dir')}</Text> + + <Text>?</Text> + <Text isSubdued>{translate('settings.analysis_scope.wildcards.single_char')}</Text> </StyledGrid> <CategoryDefinitionsList diff --git a/server/sonar-web/src/main/js/apps/settings/components/DefinitionDescription.tsx b/server/sonar-web/src/main/js/apps/settings/components/DefinitionDescription.tsx index 6afc913924e..ec6188bc0b2 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/DefinitionDescription.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/DefinitionDescription.tsx @@ -18,8 +18,8 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Text, Tooltip } from '@sonarsource/echoes-react'; -import { SafeHTMLInjection, SanitizeLevel, SubHeading } from '~design-system'; +import { Heading, Text, Tooltip } from '@sonarsource/echoes-react'; +import { SafeHTMLInjection, SanitizeLevel } from '~design-system'; import { translateWithParameters } from '../../../helpers/l10n'; import { ExtendedSettingDefinition } from '../../../types/settings'; import { getPropertyDescription, getPropertyName } from '../utils'; @@ -34,9 +34,9 @@ export default function DefinitionDescription({ definition }: Readonly<Props>) { return ( <div className="sw-w-abs-300"> - <SubHeading className="sw-text-ellipsis sw-overflow-hidden" title={propertyName}> + <Heading as="h4" className="sw-text-ellipsis sw-overflow-hidden"> {propertyName} - </SubHeading> + </Heading> {description && ( <SafeHTMLInjection htmlAsString={description} sanitizeLevel={SanitizeLevel.RESTRICTED}> diff --git a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx index 6a9f88834e8..bf9d5b732ce 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/SubCategoryDefinitionsList.tsx @@ -18,9 +18,11 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { Heading } from '@sonarsource/echoes-react'; +import classNames from 'classnames'; import { groupBy, sortBy } from 'lodash'; import * as React from 'react'; -import { BasicSeparator, Note, SafeHTMLInjection, SanitizeLevel, SubTitle } from '~design-system'; +import { BasicSeparator, Note, SafeHTMLInjection, SanitizeLevel } from '~design-system'; import { withRouter } from '~sonar-aligned/components/hoc/withRouter'; import { Location } from '~sonar-aligned/types/router'; import { SettingDefinitionAndValue } from '../../../types/settings'; @@ -81,17 +83,17 @@ class SubCategoryDefinitionsList extends React.PureComponent<SubCategoryDefiniti : sortedSubCategories.filter((c) => !SUB_CATEGORY_EXCLUSIONS[category]?.includes(c.key)); return ( - <ul> + <ul className={classNames({ 'sw-mx-6': !noPadding })}> {filteredSubCategories.map((subCategory, index) => ( - <li className={noPadding ? '' : 'sw-p-6'} key={subCategory.key}> + <li className={classNames({ 'sw-py-6': !noPadding })} key={subCategory.key}> {displaySubCategoryTitle && ( - <SubTitle - as="h2" + <Heading + as="h3" data-key={subCategory.key} ref={this.scrollToSubCategoryOrDefinition} > {subCategory.name} - </SubTitle> + </Heading> )} {subCategory.description != null && ( diff --git a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx index dfc9e4c9a83..96807c96a7f 100644 --- a/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx +++ b/server/sonar-web/src/main/js/apps/settings/components/__tests__/AnalysisScope-test.tsx @@ -32,7 +32,9 @@ const handler = new SettingsServiceMock(); const ui = { introduction: byText('settings.analysis_scope.wildcards.introduction'), - docLink: byRole('link', { name: /learn_more/ }), + docLink: byRole('link', { + name: 'settings.analysis_scope.wildcards.introduction_link open_in_new_tab', + }), }; beforeEach(() => { diff --git a/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx b/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx index e125d76f9c9..b516cabe002 100644 --- a/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx +++ b/server/sonar-web/src/main/js/components/facets/SeverityFacet.tsx @@ -62,8 +62,8 @@ export default function SeverityFacet(props: Readonly<BasicProps>) { { id: `severity_impact.help.description` }, { p1: (text) => <p>{text}</p>, p: (text) => <p className="sw-mt-4">{text}</p> }, )} - link={DocLink.CleanCodeIntroduction} - linkText={intl.formatMessage({ id: 'learn_more' })} + link={DocLink.MQRSeverity} + linkText={intl.formatMessage({ id: 'severity_impact.help.link' })} /> ) } diff --git a/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx b/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx index 3f45f75d7d6..b418e39d953 100644 --- a/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx +++ b/server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx @@ -51,7 +51,7 @@ export function CleanCodeAttributePill(props: Readonly<Props>) { )} footer={ <DocumentationLink to={DocLink.CleanCodeIntroduction}> - {translate('learn_more')} + {translate('clean_code_attribute.learn_more')} </DocumentationLink> } > diff --git a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx b/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx index 43fb6dd9856..ec6578de8c3 100644 --- a/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx +++ b/server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx @@ -144,8 +144,8 @@ export default function SoftwareImpactPill(props: Props) { </> } footer={ - <DocumentationLink to={DocLink.CleanCodeIntroduction}> - {translate('learn_more')} + <DocumentationLink shouldOpenInNewTab to={DocLink.MQRSeverity}> + {translate('severity_impact.help.link')} </DocumentationLink> } > diff --git a/server/sonar-web/src/main/js/helpers/doc-links.ts b/server/sonar-web/src/main/js/helpers/doc-links.ts index 393dcbea3e2..ca747817d8e 100644 --- a/server/sonar-web/src/main/js/helpers/doc-links.ts +++ b/server/sonar-web/src/main/js/helpers/doc-links.ts @@ -45,6 +45,7 @@ export enum DocLink { AlmSamlAuth = '/instance-administration/authentication/saml/overview/', AlmSamlScimAuth = '/instance-administration/authentication/saml/scim/overview/', AnalysisScope = '/project-administration/analysis-scope/', + AnalysisScopeWildcardPatterns = '/project-administration/analysis-scope/#wildcard-patterns', AuthOverview = '/instance-administration/authentication/overview/', BackgroundTasks = '/analyzing-source-code/background-tasks/', BranchAnalysis = '/analyzing-source-code/branch-analysis/introduction/', @@ -83,6 +84,7 @@ export enum DocLink { QualityGates = '/instance-administration/analysis-functions/quality-gates/', Root = '/', RuleSeverity = '/instance-administration/analysis-functions/quality-profiles/#rule-severity', + MQRSeverity = '/instance-administration/analysis-functions/instance-mode/mqr-mode/#mqr-severity', RulesOverview = '/user-guide/rules/overview', SecurityHotspots = '/user-guide/security-hotspots/', SecurityReports = '/user-guide/viewing-reports/security-reports/', diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index 056494d574f..863dbd92775 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -1105,6 +1105,7 @@ issue.clean_code_attribute.TESTED.advice=To be tested, the code needs to have au issue.clean_code_attribute.TRUSTWORTHY=Not trustworthy issue.clean_code_attribute.TRUSTWORTHY.title=This is a responsibility issue, the code is not trustworthy enough. issue.clean_code_attribute.TRUSTWORTHY.advice=To be trustworthy, the code needs to abstain from revealing or hard-coding private information. +clean_code_attribute.learn_more=Lear more about Clean Code issue.issue_status.OPEN=Open issue.issue_status.ACCEPTED=Accepted @@ -1521,7 +1522,9 @@ settings.search.results=Search results list settings.json.format=Format JSON settings.json.format_error=Formatting requires valid JSON. Please fix it and retry. -settings.analysis_scope.wildcards.introduction=You can use the following wildcards. +settings.analysis_scope.introduction=Narrow the focus by configure what will be analyzed and how. Learn more about <link>analysis scope</link>. +settings.analysis_scope.wildcards.introduction=You can set analysis parameters by using the following <link>wild card patterns</link>: +settings.analysis_scope.wildcards.link=wild card patterns settings.analysis_scope.wildcards.zero_more_char=Match zero or more characters settings.analysis_scope.wildcards.zero_more_dir=Match zero or more directories settings.analysis_scope.wildcards.single_char=Match a single character @@ -2389,7 +2392,7 @@ quality_profiles.activate_more.help.built_in=This quality profile is built in, a quality_profiles.activate_more_rules=Activate More Rules quality_profiles.comparison.activate_rule=Activate rule for profile "{profile}" quality_profiles.comparison.deactivate_rule=Dectivate rule for profile "{profile}" -quality_profiles.intro=Quality profiles are collections of rules to apply during an analysis. For each language there is a default profile. All projects not explicitly assigned to some other profile will be analyzed with the default. Ideally, all projects will use the same profile for a language. +quality_profiles.intro=Quality profiles are collections of rules to apply during an analysis. For each language there is a default profile. All projects not explicitly assigned to some other profile will be analyzed with the default. Ideally, all projects will use the same profile for a language. Learn more about <link>Quality Profiles</link>. quality_profiles.list.projects=Projects quality_profiles.list.projects.help=Projects assigned to a profile will always be analyzed with it for that language, regardless of which profile is the default. Quality profile administrators may assign projects to a non-default profile, or always make it follow the system default. Project administrators may choose any profile for each language. quality_profiles.list.rules=Rules @@ -2550,6 +2553,7 @@ quality_gates.built_in.description.2=It will automatically be updated with the l quality_gates.status=Quality Gate status quality_gates.help.title=What is a quality gate? quality_gates.help.desc=It`s a set of measure-based, Boolean conditions. It helps you know immediately whether your projects are production-ready. Ideally, all projects will use the same quality gate. Each project's Quality Gate status is displayed prominently on its homepage. +quality_gates.help.link=Learn more about quality gates quality_gates.permissions=Permissions quality_gates.permissions.help=Users with the global "Administer quality gates" permission and those listed below can manage this quality gate. quality_gates.permissions.grant=Grant permissions to a user or a group @@ -3153,7 +3157,7 @@ severity_impact.LOW.description=Potential for moderate to minor impact. severity_impact.INFO=Info severity_impact.INFO.description=Neither a bug nor a quality flaw. Just a finding. severity_impact.help.description=<p1>Severities are now directly tied to the software quality impacted. This means that one software quality impacted has one severity.</p1><p>They can be changed with sufficient permissions.</p> - +severity_impact.help.link=Learn more about severity and software qualities #------------------------------------------------------------------------------ # # SOFTWARE QUALITIES @@ -4232,7 +4236,7 @@ background_task.type.GITLAB_AUTH_PROVISIONING=GitLab Provisioning background_task.type.GITLAB_PROJECT_PERMISSIONS_PROVISIONING=Gitlab Project Permission Sync background_tasks.page=Background Tasks -background_tasks.page.description=This page allows monitoring of the queue of tasks running asynchronously on the server. It also gives access to the history of finished tasks and their status. Analysis report processing is the most common kind of background task. +background_tasks.page.description=This page allows monitoring of the queue of tasks running asynchronously on the server. It also gives access to the history of finished tasks and their status. Analysis report processing is the most common kind of background task. Learn more about <link>Background Tasks</link>. background_tasks.currents_filter.ONLY_CURRENTS=Only Latest Analysis |