]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22253 Extract all documentation link URLs to a separate module
authorDavid Cho-Lerat <david.cho-lerat@sonarsource.com>
Thu, 30 May 2024 06:45:19 +0000 (08:45 +0200)
committersonartech <sonartech@sonarsource.com>
Thu, 30 May 2024 20:02:37 +0000 (20:02 +0000)
129 files changed:
server/sonar-web/src/main/js/app/components/DocumentationRedirect.tsx
server/sonar-web/src/main/js/app/components/GlobalFooter.tsx
server/sonar-web/src/main/js/app/components/app-state/AppStateContext.tsx
server/sonar-web/src/main/js/app/components/indexation/IndexationNotificationRenderer.tsx
server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx
server/sonar-web/src/main/js/apps/account/Account.tsx
server/sonar-web/src/main/js/apps/audit-logs/components/AuditAppRenderer.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/BackgroundTasksApp.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/Header.tsx
server/sonar-web/src/main/js/apps/code/components/CodeAppRenderer.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/CodingRulesApp.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsHeaderActions.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleListItem.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/SeverityFacet.tsx
server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx
server/sonar-web/src/main/js/apps/create/project/components/NewCodeDefinitionSelection.tsx
server/sonar-web/src/main/js/apps/create/project/manual/ManualProjectCreate.tsx
server/sonar-web/src/main/js/apps/create/project/monorepo/MonorepoConnectionSelector.tsx
server/sonar-web/src/main/js/apps/create/project/monorepo/MonorepoProjectHeader.tsx
server/sonar-web/src/main/js/apps/groups/GroupsApp.tsx
server/sonar-web/src/main/js/apps/groups/components/Header.tsx
server/sonar-web/src/main/js/apps/issues/components/IssueGuide.tsx
server/sonar-web/src/main/js/apps/issues/components/IssueNewStatusAndTransitionGuide.tsx
server/sonar-web/src/main/js/apps/issues/components/IssueOpenInIdeButton.tsx
server/sonar-web/src/main/js/apps/issues/components/IssuesApp.tsx
server/sonar-web/src/main/js/apps/issues/components/__tests__/IssueOpenInIdeButton-test.tsx
server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx
server/sonar-web/src/main/js/apps/maintenance/components/App.tsx
server/sonar-web/src/main/js/apps/marketplace/App.tsx
server/sonar-web/src/main/js/apps/overview/branches/ApplicationNonCaycProjectWarning.tsx
server/sonar-web/src/main/js/apps/overview/branches/CleanAsYouCodeWarning.tsx
server/sonar-web/src/main/js/apps/overview/branches/MeasuresPanelNoNewCode.tsx
server/sonar-web/src/main/js/apps/overview/branches/ReplayTour.tsx
server/sonar-web/src/main/js/apps/overview/branches/TabsPanel.tsx
server/sonar-web/src/main/js/apps/overview/components/App.tsx
server/sonar-web/src/main/js/apps/permission-templates/components/PermissionTemplatesApp.tsx
server/sonar-web/src/main/js/apps/permissions/global/components/PermissionsGlobalApp.tsx
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityAppRenderer.tsx
server/sonar-web/src/main/js/apps/projectActivity/components/ProjectActivityGraphs.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/SetAsMainBranchModal.tsx
server/sonar-web/src/main/js/apps/projectInformation/projectRegulatoryReport/RegulatoryReport.tsx
server/sonar-web/src/main/js/apps/projectNewCode/components/AppHeader.tsx
server/sonar-web/src/main/js/apps/projectNewCode/components/ProjectNewCodeDefinitionApp.tsx
server/sonar-web/src/main/js/apps/projectQualityGate/ProjectQualityGateAppRenderer.tsx
server/sonar-web/src/main/js/apps/projectQualityProfiles/ProjectQualityProfilesAppRenderer.tsx
server/sonar-web/src/main/js/apps/projects/components/AllProjects.tsx
server/sonar-web/src/main/js/apps/projectsManagement/ProjectManagementApp.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CaYCConditionsSimplificationGuide.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CaycCompliantBanner.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CaycFixOptimizeBanner.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ConditionReviewAndUpdateModal.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
server/sonar-web/src/main/js/apps/quality-profiles/components/QualityProfilesApp.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/PageHeader.tsx
server/sonar-web/src/main/js/apps/security-hotspots/SecurityHotspotsAppRenderer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/EmptyHotspotsPage.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotDisabledFilterTooltip.tsx
server/sonar-web/src/main/js/apps/settings/components/AnalysisScope.tsx
server/sonar-web/src/main/js/apps/settings/components/NewCodeDefinition.tsx
server/sonar-web/src/main/js/apps/settings/components/SettingsAppRenderer.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionFormField.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AzureForm.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketCloudForm.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/BitbucketServerForm.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GithubForm.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/GitlabForm.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/Authentication.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/AutoProvisionningConsent.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/BitbucketAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/ConfigurationForm.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GitLabConfigurationForm.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/GithubAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/authentication/SamlAuthenticationTab.tsx
server/sonar-web/src/main/js/apps/settings/components/pullRequestDecorationBinding/AlmSpecificForm.tsx
server/sonar-web/src/main/js/apps/settings/encryption/EncryptionForm.tsx
server/sonar-web/src/main/js/apps/settings/encryption/GenerateSecretKeyForm.tsx
server/sonar-web/src/main/js/apps/system/components/SystemApp.tsx
server/sonar-web/src/main/js/apps/users/Header.tsx
server/sonar-web/src/main/js/apps/users/UsersApp.tsx
server/sonar-web/src/main/js/apps/users/components/DeactivateForm.tsx
server/sonar-web/src/main/js/apps/web-api/components/WebApiApp.tsx
server/sonar-web/src/main/js/apps/webhooks/components/App.tsx
server/sonar-web/src/main/js/apps/webhooks/components/PageHeader.tsx
server/sonar-web/src/main/js/components/common/DocumentationLink.tsx
server/sonar-web/src/main/js/components/embed-docs-modal/DocItemLink.tsx
server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsPopup.tsx
server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json [deleted file]
server/sonar-web/src/main/js/components/embed-docs-modal/Suggestions.tsx
server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsContext.ts
server/sonar-web/src/main/js/components/embed-docs-modal/SuggestionsProvider.tsx
server/sonar-web/src/main/js/components/embed-docs-modal/__tests__/EmbedDocsPopup-test.tsx
server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx
server/sonar-web/src/main/js/components/issue/components/IssueType.tsx
server/sonar-web/src/main/js/components/new-code-definition/BranchNCDAutoUpdateMessage.tsx
server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionAnalysisWarning.tsx
server/sonar-web/src/main/js/components/new-code-definition/NewCodeDefinitionDaysOption.tsx
server/sonar-web/src/main/js/components/shared/AnalysisMissingInfoMessage.tsx
server/sonar-web/src/main/js/components/shared/AppVersionStatus.tsx
server/sonar-web/src/main/js/components/shared/CleanCodeAttributePill.tsx
server/sonar-web/src/main/js/components/shared/SoftwareImpactPill.tsx
server/sonar-web/src/main/js/components/tutorials/__tests__/TutorialSelection-it.tsx
server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/AlertClassicEditor.tsx
server/sonar-web/src/main/js/components/tutorials/azure-pipelines/commands/PublishSteps.tsx
server/sonar-web/src/main/js/components/tutorials/components/CompilationInfo.tsx
server/sonar-web/src/main/js/components/tutorials/components/ProjectTokenScopeInfo.tsx
server/sonar-web/src/main/js/components/tutorials/github-action/commands/MonorepoDocLinkFallback.tsx
server/sonar-web/src/main/js/components/tutorials/jenkins/PreRequisitesStep.tsx
server/sonar-web/src/main/js/components/tutorials/other/DoneNextSteps.tsx
server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetExecute.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DotNetFramework.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/DownloadScanner.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/ExecBuildWrapper.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/ExecScanner.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/JavaGradle.tsx
server/sonar-web/src/main/js/components/tutorials/other/commands/JavaMaven.tsx
server/sonar-web/src/main/js/components/upgrade/SystemUpgradeItem.tsx
server/sonar-web/src/main/js/helpers/constants.ts
server/sonar-web/src/main/js/helpers/doc-links.ts [new file with mode: 0644]
server/sonar-web/src/main/js/helpers/docs.ts
server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx
server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx
server/sonar-web/src/main/js/types/types.ts

index ce07d94d59ded75be6071b7d9e7ab147aa7eb863..ebfdf4c0cc937dadfbdaad433456ff59304db06a 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { Link } from 'design-system';
+
+import { LinkStandalone } from '@sonarsource/echoes-react';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { useLocation } from 'react-router-dom';
-import { useDocUrl } from '../../helpers/docs';
+import { useUncataloguedDocUrl } from '../../helpers/docs';
 
 const PAUSE_REDIRECT = 1;
 
 export default function DocumentationRedirect() {
   const location = useLocation();
-  const url = useDocUrl(location.pathname.replace(/^\/documentation/, ''));
+  const url = useUncataloguedDocUrl(location.pathname.replace(/^\/documentation/, '')) as string;
 
   return (
     <>
@@ -40,7 +41,9 @@ export default function DocumentationRedirect() {
           <span className="global-loading-text">Redirecting...</span>
         </div>
         <div>
-          <Link to={url}>Click here if you&apos;re not being redirected automatically</Link>
+          <LinkStandalone to={url}>
+            Click here if you&apos;re not being redirected automatically
+          </LinkStandalone>
         </div>
       </div>
     </>
index 098292751bf85ab593828dd6538c5efa19117590..88cc3c8617071340a59922f1f3977e1f294aec94 100644 (file)
@@ -31,6 +31,7 @@ import React from 'react';
 import { useIntl } from 'react-intl';
 import InstanceMessage from '../../components/common/InstanceMessage';
 import AppVersionStatus from '../../components/shared/AppVersionStatus';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 import { getEdition } from '../../helpers/editions';
 import GlobalFooterBranding from './GlobalFooterBranding';
@@ -97,7 +98,7 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter
             </li>
 
             <li>
-              <LinkStandalone highlight={LinkHighlight.CurrentColor} to={docUrl('/')}>
+              <LinkStandalone highlight={LinkHighlight.CurrentColor} to={docUrl(DocLink.Root)}>
                 {intl.formatMessage({ id: 'footer.documentation' })}
               </LinkStandalone>
             </li>
@@ -105,7 +106,7 @@ export default function GlobalFooter({ hideLoggedInInfo }: Readonly<GlobalFooter
             <li>
               <LinkStandalone
                 highlight={LinkHighlight.CurrentColor}
-                to={docUrl('/instance-administration/plugin-version-matrix/')}
+                to={docUrl(DocLink.InstanceAdminPluginVersionMatrix)}
               >
                 {intl.formatMessage({ id: 'footer.plugins' })}
               </LinkStandalone>
index 4492d1c18d61270d4575f1daaa63db1fc1dad62b..1d88b1d220eb7a4aa21cabd2743a0ad1c036ff29 100644 (file)
@@ -17,7 +17,9 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import * as React from 'react';
+import { DOC_URL } from '../../../helpers/doc-links';
 import { AppState } from '../../../types/appstate';
 
 export const DEFAULT_APP_STATE = {
@@ -29,6 +31,6 @@ export const DEFAULT_APP_STATE = {
   settings: {},
   version: '',
   versionEOL: '',
-  documentationUrl: 'https://docs.sonarsource.com/sonarqube/latest',
+  documentationUrl: DOC_URL,
 };
 export const AppStateContext = React.createContext<AppState>(DEFAULT_APP_STATE);
index 72561a3e5b92741f5ee794e5790090c8842ff0f3..63d1429414ac9364f8afd0ed6842f1d9870e0864 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 /* eslint-disable react/no-unused-prop-types */
 import styled from '@emotion/styled';
 import {
@@ -33,6 +34,7 @@ import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { queryToSearchString } from '~sonar-aligned/helpers/urls';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { IndexationNotificationType } from '../../../types/indexation';
 import { TaskStatuses, TaskTypes } from '../../../types/tasks';
@@ -215,7 +217,7 @@ function renderBackgroundTasksPageLink(hasError: boolean, text: string) {
 
 function renderIndexationDocPageLink() {
   return (
-    <DocumentationLink className="sw-whitespace-nowrap" to="/instance-administration/reindexing/">
+    <DocumentationLink className="sw-whitespace-nowrap" to={DocLink.InstanceAdminReindexation}>
       <FormattedMessage id="indexation.features_partly_available.link" />
     </DocumentationLink>
   );
index 7f97acc9051246ed5e817056e4cca1e59f3ce1f7..6d6f4aa61d5a01b7bef45da30a79ffbfebcce291 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link } from '@sonarsource/echoes-react';
 import { HelperHintIcon } from 'design-system';
 import React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
+import { DocLink } from '../../../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../../../helpers/l10n';
 import { getApplicationAdminUrl } from '../../../../../helpers/urls';
 import { useProjectBindingQuery } from '../../../../../queries/devops-integration';
@@ -103,18 +105,18 @@ export default function BranchHelpTooltip({
           data-test="only-one-branch-like"
           links={[
             {
-              href: '/analyzing-source-code/branches/branch-analysis/',
+              href: DocLink.BranchAnalysis,
               label: translate('branch_like_navigation.only_one_branch.documentation'),
             },
             {
-              href: '/analyzing-source-code/pull-request-analysis',
+              href: DocLink.PullRequestAnalysis,
               label: translate('branch_like_navigation.only_one_branch.pr_analysis'),
             },
             {
+              doc: false,
               href: `/tutorials?id=${component.key}`,
-              label: translate('branch_like_navigation.tutorial_for_ci'),
               inPlace: true,
-              doc: false,
+              label: translate('branch_like_navigation.tutorial_for_ci'),
             },
           ]}
           title={translate('branch_like_navigation.only_one_branch.title')}
index 8521ac7a0b8d0d7e74c7fffcb0066ffd585d662d..84a1b46b1f5f5ae2c06bad21843e1dbc14411784 100644 (file)
@@ -25,7 +25,6 @@ import { Helmet } from 'react-helmet-async';
 import { Outlet } from 'react-router-dom';
 import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import { useCurrentLoginUser } from '../../app/components/current-user/CurrentUserContext';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { translate, translateWithParameters } from '../../helpers/l10n';
 import Nav from './components/Nav';
 import UserCard from './components/UserCard';
@@ -59,8 +58,6 @@ export default function Account() {
 
       <LargeCenteredLayout as="main">
         <PageContentFontWrapper className="sw-body-sm sw-py-8">
-          <Suggestions suggestions="account" />
-
           <Helmet
             defaultTitle={title}
             defer={false}
index 4b4dfd815863053738c4da8e54e6c784b8ab19b6..1ba1ff7fe1c7a43b70f1fc9a637641ff025b2116 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link, RadioButtonGroup } from '@sonarsource/echoes-react';
 import { subDays } from 'date-fns';
 import {
@@ -30,7 +31,6 @@ import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { FormattedMessage } from 'react-intl';
 import { queryToSearchString } from '~sonar-aligned/helpers/urls';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { now } from '../../../helpers/dates';
 import { translate } from '../../../helpers/l10n';
 import '../style.css';
@@ -79,7 +79,6 @@ export default function AuditAppRenderer(props: Readonly<AuditAppRendererProps>)
   return (
     <LargeCenteredLayout as="main" id="audit-logs-page">
       <PageContentFontWrapper className="sw-body-sm sw-my-8">
-        <Suggestions suggestions="audit-logs" />
         <Helmet title={translate('audit_logs.page')} />
 
         <Title>{translate('audit_logs.page')}</Title>
index b5539eb3fccf84a49bf05f8234a78cbd40e8341b..c5b584c14ea3c3ea1839bbb7d6fe6cc3ce2fe3e3 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Spinner } from '@sonarsource/echoes-react';
 import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system';
 import { debounce } from 'lodash';
@@ -35,6 +36,7 @@ import withComponentContext from '../../../app/components/componentContext/withC
 import ListFooter from '../../../components/controls/ListFooter';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { toShortISO8601String } from '../../../helpers/dates';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { parseAsDate } from '../../../helpers/query';
 import { Task, TaskStatuses } from '../../../types/tasks';
@@ -227,7 +229,7 @@ export class BackgroundTasksApp extends React.PureComponent<Props, State> {
     return (
       <LargeCenteredLayout id="background-tasks">
         <PageContentFontWrapper className="sw-my-4 sw-body-sm">
-          <Suggestions suggestions="background_tasks" />
+          <Suggestions suggestion={DocLink.BackgroundTasks} />
           <Helmet defer={false} title={translate('background_tasks.page')} />
           <Spinner isLoading={!types}>
             <Header component={component} />
index 821621de0ffed775b116825c1bd1170a7575a878..275e3adf8f6037b570ff710362c6db4eb325c2f6 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Title } from 'design-system';
 import * as React from 'react';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Component } from '../../../types/types';
 import Workers from './Workers';
@@ -35,7 +37,7 @@ export default function Header(props: Readonly<Props>) {
         <Title className="sw-mb-4">{translate('background_tasks.page')}</Title>
         <p className="sw-max-w-3/4">
           {translate('background_tasks.page.description')}
-          <DocumentationLink className="sw-ml-2" to="/analyzing-source-code/background-tasks/">
+          <DocumentationLink className="sw-ml-2" to={DocLink.BackgroundTasks}>
             {translate('learn_more')}
           </DocumentationLink>
         </p>
index 3f514a8e07617d6d7b0f0d94f9df8697d13be010..9072e7221c7d6338c248c9c0a37710458b6dc117 100644 (file)
@@ -35,7 +35,6 @@ import { isPortfolioLike } from '~sonar-aligned/helpers/component';
 import { Breadcrumb } from '~sonar-aligned/types/component';
 import { Location } from '~sonar-aligned/types/router';
 import ListFooter from '../../../components/controls/ListFooter';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import AnalysisMissingInfoMessage from '../../../components/shared/AnalysisMissingInfoMessage';
 import { CCT_SOFTWARE_QUALITY_METRICS, OLD_TAXONOMY_METRICS } from '../../../helpers/constants';
 import { KeyboardKeys } from '../../../helpers/keycodes';
@@ -125,7 +124,6 @@ export default function CodeAppRenderer(props: Readonly<Props>) {
 
   return (
     <LargeCenteredLayout className="sw-py-8 sw-body-md" id="code-page">
-      <Suggestions suggestions="code" />
       <Helmet defer={false} title={sourceViewer !== undefined ? sourceViewer.name : defaultTitle} />
 
       <A11ySkipTarget anchor="code_main" />
index 087d44a1086191eb2cf41a8b11f935ccfc62f99a..f5af3a127381737e981d3913d76686d0bc316338 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonPrimary,
   FlagMessage,
@@ -31,6 +32,7 @@ import {
 import * as React from 'react';
 import { Profile } from '../../../api/quality-profiles';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { sanitizeString } from '../../../helpers/sanitize';
 import { useActivateRuleMutation } from '../../../queries/quality-profiles';
@@ -119,7 +121,7 @@ export default function ActivationFormModal(props: Readonly<Props>) {
             {translate('coding_rules.severity_deprecated')}
             <DocumentationLink
               className="sw-ml-2 sw-whitespace-nowrap"
-              to="/user-guide/clean-code/introduction/"
+              to={DocLink.CleanCodeIntroduction}
             >
               {translate('learn_more')}
             </DocumentationLink>
index 5c1e289b1513b7af5e8f263663ea8a2c5a3c0155..970b3a959e6a50dca3af0ce1de43b966e097064f 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import {
   InputSearch,
@@ -40,6 +41,7 @@ import withCurrentUserContext from '../../../app/components/current-user/withCur
 import ListFooter from '../../../components/controls/ListFooter';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import '../../../components/search-navigator.css';
+import { DocLink } from '../../../helpers/doc-links';
 import { isInput, isShortcut } from '../../../helpers/keyboardEventHelpers';
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
@@ -566,7 +568,7 @@ export class CodingRulesApp extends React.PureComponent<Props, State> {
 
     return (
       <>
-        <Suggestions suggestions="coding_rules" />
+        <Suggestions suggestion={DocLink.InstanceAdminQualityProfiles} />
         {openRule ? (
           <Helmet
             defer={false}
index 480ba05fb860e2e0d62d80377e2a241980d88de5..4d16aa936424e22b86d5ec7872cdd1061841d78a 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import { FacetBox, FacetItem, HelperHintIcon, Note, themeColor } from 'design-system';
 import { sortBy } from 'lodash';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import { Profile } from '../../../api/quality-profiles';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Dict } from '../../../types/types';
 import { FacetItemsList } from '../../issues/sidebar/FacetItemsList';
@@ -179,7 +181,7 @@ export default class ProfileFacet extends React.PureComponent<Props> {
             content={translate('coding_rules.facet.qprofile.help')}
             links={[
               {
-                href: '/instance-administration/quality-profiles/',
+                href: DocLink.InstanceAdminQualityProfiles,
                 label: translate('coding_rules.facet.qprofile.link'),
               },
             ]}
index 46d82b187b40a8e9af6fe871cb3ab23162627497..e9b3835e384872daca549bfb776a43ce2bc335f0 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Note, SeparatorCircleIcon, TextSubdued } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import IssueSeverityIcon from '../../../components/icon-mappers/IssueSeverityIcon';
 import IssueTypeIcon from '../../../components/icon-mappers/IssueTypeIcon';
 import TagsList from '../../../components/tags/TagsList';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { IssueSeverity } from '../../../types/issues';
 import { Dict, RuleDetails } from '../../../types/types';
@@ -53,7 +55,7 @@ export default function RuleDetailsHeaderActions(props: Readonly<Props>) {
         }
         links={[
           {
-            href: '/user-guide/rules/overview',
+            href: DocLink.RulesOverview,
             label: translate('learn_more'),
           },
         ]}
@@ -84,7 +86,7 @@ export default function RuleDetailsHeaderActions(props: Readonly<Props>) {
         }
         links={[
           {
-            href: '/user-guide/rules/overview',
+            href: DocLink.RulesOverview,
             label: translate('learn_more'),
           },
         ]}
index 81aba54fac13bd59c124eb935c82e97ad384f5eb..8351a52a53441b8fad512426025dfcc6969473b2 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import {
   Badge,
@@ -37,6 +38,7 @@ import { CleanCodeAttributePill } from '../../../components/shared/CleanCodeAttr
 import SoftwareImpactPillList from '../../../components/shared/SoftwareImpactPillList';
 import TypeHelper from '../../../components/shared/TypeHelper';
 import TagsList from '../../../components/tags/TagsList';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getRuleUrl } from '../../../helpers/urls';
 import { Rule } from '../../../types/types';
@@ -254,7 +256,7 @@ export default class RuleListItem extends React.PureComponent<Props> {
                   }
                   links={[
                     {
-                      href: '/user-guide/clean-code/introduction',
+                      href: DocLink.CleanCodeIntroduction,
                       label: translate('learn_more'),
                     },
                   ]}
index 7e6e1d124e91a2f48a0b00c2aaab4dca74a4b953..6acfbcc3871d13f735971b92452bbec33ee6c710 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
 import { IMPACT_SEVERITIES } from '../../../helpers/constants';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import Facet, { BasicProps } from './Facet';
 
@@ -59,7 +61,7 @@ export default function SeverityFacet(props: BasicProps) {
           }
           links={[
             {
-              href: '/user-guide/clean-code/introduction',
+              href: DocLink.CleanCodeIntroduction,
               label: translate('learn_more'),
             },
           ]}
index 9eccd8c6154fff0888cca667210e750d93b9b811..343b6cd4acc97fb1fafbde62981fe40ae96fe096 100644 (file)
@@ -287,7 +287,7 @@ class ComponentMeasuresApp extends React.PureComponent<Props, State> {
 
     return (
       <LargeCenteredLayout id="component-measures" className="sw-pt-8">
-        <Suggestions suggestions="component_measures" />
+        <Suggestions suggestionGroup="component_measures" />
         <Helmet defer={false} title={translate('layout.measures')} />
         <PageContentFontWrapper className="sw-body-sm">
           <Spinner isLoading={this.state.loading} />
index 12389b26b7cc3f2e4be9daaf3046a14dce9a4394..43e1b37568f779d2ebe000c46a0601dc59f1a008 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonPrimary,
   ButtonSecondary,
@@ -37,6 +38,7 @@ import { useNavigate, unstable_usePrompt as usePrompt } from 'react-router-dom';
 import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
 import { queryToSearchString } from '~sonar-aligned/helpers/urls';
 import NewCodeDefinitionSelector from '../../../../components/new-code-definition/NewCodeDefinitionSelector';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { getProjectUrl } from '../../../../helpers/urls';
@@ -69,7 +71,7 @@ export default function NewCodeDefinitionSelection(props: Props) {
   const intl = useIntl();
   const location = useLocation();
   const navigate = useNavigate();
-  const getDocUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.NewCodeDefinition);
   usePrompt({
     when: isImporting,
     message: translate('onboarding.create_project.please_dont_leave'),
@@ -215,11 +217,7 @@ export default function NewCodeDefinitionSelection(props: Props) {
           id="onboarding.create_project.new_code_definition.description"
           values={{
             link: (
-              <Link
-                to={getDocUrl(
-                  '/project-administration/clean-as-you-code-settings/defining-new-code/',
-                )}
-              >
+              <Link to={docUrl}>
                 {translate('onboarding.create_project.new_code_definition.description.link')}
               </Link>
             ),
index 6804fc11ddf4341897185f72752cb0813215dcff..3663ddbd302a86209c758b997a0b21f6b4b45df2 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import classNames from 'classnames';
 import {
   ButtonPrimary,
@@ -36,6 +37,7 @@ import { isEmpty } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import { getValue } from '../../../../api/settings';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { GlobalSettingKeys } from '../../../../types/settings';
@@ -70,7 +72,7 @@ export default function ManualProjectCreate(props: Readonly<Props>) {
   });
 
   const intl = useIntl();
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.BranchAnalysis);
 
   React.useEffect(() => {
     async function fetchMainBranchName() {
@@ -194,11 +196,7 @@ export default function ManualProjectCreate(props: Readonly<Props>) {
                 id="onboarding.create_project.main_branch_name.description"
                 defaultMessage={translate('onboarding.create_project.main_branch_name.description')}
                 values={{
-                  learn_more: (
-                    <Link to={docUrl('/analyzing-source-code/branches/branch-analysis')}>
-                      {translate('learn_more')}
-                    </Link>
-                  ),
+                  learn_more: <Link to={docUrl}>{translate('learn_more')}</Link>,
                 }}
               />
             </Note>
index db6ac2b47bc083b37bb6e2310c9b389169b9da01..9025f7e73913aacfc2be804b4bc8f89b68c2cf33 100644 (file)
@@ -17,7 +17,8 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { Title } from 'design-system/lib';
+
+import { Title } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { GroupBase } from 'react-select';
index 1c1dad765285917d77d5e79671c24d46e627bfd7..ae8fc6f4182220d67b66bd88dfcae3ee4e5a81a6 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { LinkStandalone } from '@sonarsource/echoes-react';
-import { LightPrimary, Title } from 'design-system/lib';
+import { LightPrimary, Title } from 'design-system';
 import React from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import { useLocation } from '~sonar-aligned/components/hoc/withRouter';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 
 export function MonorepoProjectHeader() {
@@ -45,7 +47,7 @@ export function MonorepoProjectHeader() {
         </LightPrimary>
       </div>
       <div className="sw-mt-3">
-        <LinkStandalone isExternal to={useDocUrl('/project-administration/monorepos/')}>
+        <LinkStandalone isExternal to={useDocUrl(DocLink.Monorepos)}>
           <FormattedMessage id="onboarding.create_project.monorepo.doc_link" />
         </LinkStandalone>
       </div>
index 952985e7eceeced2dd7196f339450071d7249bf6..6e79893b4ebab4e0d74e7232ff0073039c2f0cdc 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { InputSearch, LargeCenteredLayout, PageContentFontWrapper } from 'design-system';
 import * as React from 'react';
 import { useState } from 'react';
@@ -25,7 +26,6 @@ import GitHubSynchronisationWarning from '../../app/components/GitHubSynchronisa
 import GitLabSynchronisationWarning from '../../app/components/GitLabSynchronisationWarning';
 import ListFooter from '../../components/controls/ListFooter';
 import { ManagedFilter } from '../../components/controls/ManagedFilter';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../helpers/l10n';
 import { useGroupsQueries } from '../../queries/groups';
 import { useIdentityProviderQuery } from '../../queries/identity-provider/common';
@@ -48,7 +48,6 @@ export default function GroupsApp() {
   return (
     <LargeCenteredLayout>
       <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-        <Suggestions suggestions="user_groups" />
         <Helmet defer={false} title={translate('user_groups.page')} />
         <main>
           <Header manageProvider={manageProvider?.provider} />
index b65ef05e0286732748eb664ad48e6a039ed73b67..b2adc904b51c09ad24655a639036b550cdd0cdd0 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, FlagMessage, Title } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Provider } from '../../../types/types';
 import GroupForm from './GroupForm';
@@ -57,7 +59,7 @@ export default function Header({ manageProvider }: Readonly<HeaderProps>) {
                 values={{
                   provider: manageProvider,
                   link: (
-                    <DocumentationLink to="/instance-administration/authentication/overview/">
+                    <DocumentationLink to={DocLink.AuthOverview}>
                       {translate('documentation')}
                     </DocumentationLink>
                   ),
index 32e94ac3f4bc2ab35dfe81238f63ae37f9976caa..adab92443648baf2ca534017226ccf98099527b1 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { SpotlightTour, SpotlightTourStep } from 'design-system';
 import React, { useState } from 'react';
 import { FormattedMessage } from 'react-intl';
@@ -25,6 +26,7 @@ import { dismissNotice } from '../../../api/users';
 import { CurrentUserContext } from '../../../app/components/current-user/CurrentUserContext';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { SCREEN_POSITION_COMPUTE_DELAY } from '../../../components/common/ScreenPositionHelper';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { NoticeType } from '../../../types/users';
 
@@ -153,7 +155,7 @@ export default function IssueGuide({ run }: Props) {
           defaultMessage={translate('guiding.issue_list.5.content')}
           values={{
             link: (
-              <DocumentationLink to="/user-guide/clean-code/introduction" className="sw-capitalize">
+              <DocumentationLink to={DocLink.CleanCodeIntroduction} className="sw-capitalize">
                 {translate('documentation')}
               </DocumentationLink>
             ),
index e6864f987304d51cd88deafd9e8476bcc0e97bf6..7f83156f91a8c540d37f099df48155312eb992ba 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { SpotlightTour, SpotlightTourStep } from 'design-system';
 import React, { useState } from 'react';
 import { useIntl } from 'react-intl';
@@ -24,6 +25,7 @@ import { CallBackProps } from 'react-joyride';
 import { useCurrentUser } from '../../../app/components/current-user/CurrentUserContext';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { SCREEN_POSITION_COMPUTE_DELAY } from '../../../components/common/ScreenPositionHelper';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDismissNoticeMutation } from '../../../queries/users';
 import { IssueTransition } from '../../../types/issues';
 import { Issue } from '../../../types/types';
@@ -36,7 +38,6 @@ interface Props {
 }
 
 const PLACEMENT_RIGHT = 'right';
-const DOC_LINK = '/user-guide/issues/#statuses';
 export const SESSION_STORAGE_TRANSITION_GUIDE_KEY = 'issueNewStatusAndTransitionGuideStep';
 const EXTRA_DELAY = 100;
 const GUIDE_WIDTH = 360;
@@ -145,7 +146,7 @@ export default function IssueNewStatusAndTransitionGuide(props: Readonly<Props>)
           <span>{intl.formatMessage({ id: `guiding.issue_accept.${stepIndex}.content.1` })}</span>
           <span>{intl.formatMessage({ id: `guiding.issue_accept.${stepIndex}.content.2` })}</span>
         </div>
-        <DocumentationLink to={DOC_LINK} className="sw-mt-1 sw-inline-block">
+        <DocumentationLink to={DocLink.IssueStatuses} className="sw-mt-1 sw-inline-block">
           {intl.formatMessage({ id: `guiding.issue_accept.${stepIndex}.content.link` })}
         </DocumentationLink>
       </>
index 8a1ab07731c2bcdf39f714c1075bafc3a70e3a15..63852374650875f993bebd0d5c8c04b9de97607b 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonSecondary,
   DropdownMenu,
@@ -30,6 +31,7 @@ import {
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import {
   generateSonarLintUserToken,
@@ -58,7 +60,7 @@ const showError = () =>
       id="issues.open_in_ide.failure"
       values={{
         link: (
-          <DocumentationLink to="user-guide/sonarlint-connected-mode/">
+          <DocumentationLink to={DocLink.SonarLintConnectedMode}>
             {translate('sonarlint-connected-mode-doc')}
           </DocumentationLink>
         ),
index 3ba705f36a25589cb0892f4d60199aa1754657e8..60df939d6d0021420b5edae814dad98ce7130f3d 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import { Checkbox, Spinner } from '@sonarsource/echoes-react';
 import classNames from 'classnames';
@@ -47,7 +48,6 @@ import withCurrentUserContext from '../../../app/components/current-user/withCur
 import EmptySearch from '../../../components/common/EmptySearch';
 import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
 import ListFooter from '../../../components/controls/ListFooter';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import withIndexationContext, {
   WithIndexationContextProps,
 } from '../../../components/hoc/withIndexationContext';
@@ -1299,8 +1299,6 @@ export class App extends React.PureComponent<Props, State> {
         <LargeCenteredLayout>
           <PageContentFontWrapper className="sw-body-sm">
             <div className="sw-w-full sw-flex" id="issues-page">
-              <Suggestions suggestions="issues" />
-
               {openIssue ? (
                 <Helmet
                   defer={false}
index 3dc7783093f90260b8220ce8ab2554801c0fa4d1..7fe54312832d59f707c40078951e2225460cb324 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import { addGlobalErrorMessage, addGlobalSuccessMessage } from 'design-system';
@@ -24,6 +25,7 @@ import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import UserTokensMock from '../../../../api/mocks/UserTokensMock';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import {
   openIssue as openSonarLintIssue,
   probeSonarLintServers,
@@ -97,7 +99,7 @@ it('handles button click with no ide found', async () => {
       id="issues.open_in_ide.failure"
       values={{
         link: (
-          <DocumentationLink to="user-guide/sonarlint-connected-mode/">
+          <DocumentationLink to={DocLink.SonarLintConnectedMode}>
             sonarlint-connected-mode-doc
           </DocumentationLink>
         ),
index 68d0102e30dfb3e1c4d95792645b1e140e99dcff..d4be7b73af16f2e77947ab09d450d8b3bd5617dc 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
 import { IMPACT_SEVERITIES } from '../../../helpers/constants';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { SoftwareImpactSeverity } from '../../../types/clean-code-taxonomy';
 import { CommonProps, SimpleListStyleFacet } from './SimpleListStyleFacet';
@@ -53,7 +55,7 @@ export function SeverityFacet(props: Props) {
           }
           links={[
             {
-              href: '/user-guide/clean-code/introduction',
+              href: DocLink.CleanCodeIntroduction,
               label: translate('learn_more'),
             },
           ]}
index 90a89d048fd00cf297196ca9a06e9b1aaf23c4e4..57b0e4383da6a5bf4633c260a2c3234775475186 100644 (file)
@@ -29,6 +29,7 @@ import DocumentationLink from '../../../components/common/DocumentationLink';
 import InstanceMessage from '../../../components/common/InstanceMessage';
 import DateFromNow from '../../../components/intl/DateFromNow';
 import TimeFormatter from '../../../components/intl/TimeFormatter';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { getBaseUrl } from '../../../helpers/system';
 import { isDefined } from '../../../helpers/types';
@@ -264,7 +265,7 @@ export default class App extends React.PureComponent<Props, State> {
                     id="maintenance.sonarqube_is_under_maintenance.2"
                     values={{
                       link: (
-                        <DocumentationLink to="/setup-and-upgrade/upgrade-the-server/roadmap/">
+                        <DocumentationLink to={DocLink.ServerUpgradeRoadmap}>
                           {translate('maintenance.sonarqube_is_under_maintenance_link.2')}
                         </DocumentationLink>
                       ),
index 2046602b6d74f09c1008fb6cfb950874845e6b34..87e7faaaaf0135d4fd9dbd6d8b143024e33de637 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   BasicSeparator,
   FlagMessage,
@@ -35,7 +36,7 @@ import { getAvailablePlugins, getInstalledPlugins } from '../../api/plugins';
 import { getValue, setSimpleSettingValue } from '../../api/settings';
 import DocumentationLink from '../../components/common/DocumentationLink';
 import ListFooter from '../../components/controls/ListFooter';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { EditionKey } from '../../types/editions';
 import { PendingPluginResult, Plugin, RiskConsent } from '../../types/plugins';
@@ -167,7 +168,6 @@ class App extends React.PureComponent<Props, State> {
     return (
       <LargeCenteredLayout as="main" id="marketplace-page">
         <PageContentFontWrapper className="sw-body-sm sw-py-8">
-          <Suggestions suggestions="marketplace" />
           <Helmet title={translate('marketplace.page')} />
           <Header currentEdition={currentEdition} />
           <EditionBoxes currentEdition={currentEdition} />
@@ -186,7 +186,7 @@ class App extends React.PureComponent<Props, State> {
                       defaultMessage={translate('marketplace.page.plugins.description2')}
                       values={{
                         link: (
-                          <DocumentationLink to="/instance-administration/marketplace/">
+                          <DocumentationLink to={DocLink.InstanceAdminMarketplace}>
                             {translate('marketplace.page.plugins.description2.link')}
                           </DocumentationLink>
                         ),
index 3ac624b1b814a6360b31b2cb7142d66f4768af6e..454a97744839838562883456e40b014da833c4fd 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Card, FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { getBranchLikeQuery } from '~sonar-aligned/helpers/branch-like';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getProjectQueryUrl } from '../../../helpers/urls';
@@ -30,7 +32,7 @@ interface Props {
 }
 
 export default function ApplicationNonCaycProjectWarning({ projects }: Props) {
-  const caycUrl = useDocUrl('/user-guide/clean-as-you-code/');
+  const caycUrl = useDocUrl(DocLink.CaYC);
 
   return (
     <Card className="sw-mt-4 sw-body-sm">
index 80329d7672b1a2584cb2f91eb3c3d74b55aaf3f3..b18f457346edaaea110e9c41d6979cddcff7e67c 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { DiscreetLink, FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 import { getQualityGateUrl } from '../../../helpers/urls';
@@ -30,7 +32,7 @@ interface Props {
 }
 
 export default function CleanAsYouCodeWarning({ component }: Props) {
-  const caycUrl = useDocUrl('/user-guide/clean-as-you-code/');
+  const caycUrl = useDocUrl(DocLink.CaYC);
 
   return (
     <>
index f83bfb0f8581e55208e8c7725ad6987b897f68d7..ee764a4f15d51dec55e88cb3129abae232abb6dc 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link } from '@sonarsource/echoes-react';
 import { Note, getTabPanelId } from 'design-system';
 import * as React from 'react';
@@ -26,6 +27,7 @@ import { queryToSearchString } from '~sonar-aligned/helpers/urls';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { Image } from '../../../components/common/Image';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { CodeScope } from '../../../helpers/urls';
 import { Branch } from '../../../types/branch-like';
@@ -109,9 +111,7 @@ export default function MeasuresPanelNoNewCode(props: MeasuresPanelNoNewCodeProp
               id="overview.measures.empty_link"
               values={{
                 learn_more_link: (
-                  <DocumentationLink to="/user-guide/clean-as-you-code/">
-                    {translate('learn_more')}
-                  </DocumentationLink>
+                  <DocumentationLink to={DocLink.CaYC}>{translate('learn_more')}</DocumentationLink>
                 ),
               }}
             />
index 5ea043a93a16a860169beb0813f3c1a0eb6df49e..14de43615a9b7e7dfb41c884eec507d20147e222 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { SpotlightTour, SpotlightTourStep } from 'design-system';
 import React from 'react';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
@@ -37,7 +39,7 @@ export default function ReplayTourGuide({ run, closeTour, tourCompleted }: Reado
 
   const constructContent = (first: string) => <p className="sw-mt-2">{translate(first)}</p>;
 
-  const docUrl = useDocUrl('improving/clean-as-you-code/');
+  const docUrl = useDocUrl(DocLink.CaYC);
 
   const steps: SpotlightTourStep[] = [
     {
index 72b3839f8a2b4621bdd10c36a50eba102db38857..a7f6537c34ea23f588a554c305e87cfe1ed27a28 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Spinner } from '@sonarsource/echoes-react';
 import { isBefore, sub } from 'date-fns';
 import { ButtonLink, FlagMessage, LightLabel, Tabs } from 'design-system';
@@ -24,6 +25,7 @@ import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { isDiffMetric } from '../../../helpers/measures';
 import { CodeScope } from '../../../helpers/urls';
@@ -174,7 +176,7 @@ export function TabsPanel(props: React.PropsWithChildren<MeasuresPanelProps>) {
                 )}`}
                 <DocumentationLink
                   className="sw-ml-1 sw-whitespace-nowrap"
-                  to="/instance-administration/reindexing/"
+                  to={DocLink.InstanceAdminReindexation}
                 >
                   {translate('learn_more')}
                 </DocumentationLink>
index a4920fc60c867aee722d0748ddf64abf20935419..ead3f2d259e88b6d40795407a4c6ca4514871d41 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { isPullRequest } from '~sonar-aligned/helpers/branch-like';
@@ -54,12 +55,12 @@ export function App(props: AppProps) {
       <Helmet defer={false} title={translate('overview.page')} />
       {isPullRequest(branchLike) ? (
         <main>
-          <Suggestions suggestions="pull_requests" />
+          <Suggestions suggestionGroup="pull_requests" />
           <PullRequestOverview pullRequest={branchLike} component={component} />
         </main>
       ) : (
         <main>
-          <Suggestions suggestions="overview" />
+          <Suggestions suggestionGroup="overview" />
 
           {!component.analysisDate && (
             <EmptyOverview
index 451c29772d87b73b768200a1b8fef924a39f8939..e9305f632b847220d10fd3a07e75be5698a06ac5 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { Location } from '~sonar-aligned/types/router';
 import { getPermissionTemplates } from '../../../api/permissions';
 import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../../helpers/l10n';
 import { AppState } from '../../../types/appstate';
 import { Permission, PermissionTemplate } from '../../../types/types';
@@ -102,7 +102,6 @@ class PermissionTemplatesApp extends React.PureComponent<Props, State> {
     const { permissionTemplates, permissions, ready } = this.state;
     return (
       <>
-        <Suggestions suggestions="permission_templates" />
         <Helmet defer={false} title={translate('permission_templates.page')} />
 
         {id === undefined ? (
index d3d91fd2a1bfc1807d1fcf5d6574fbf6f1983777..c22a320554e188289dc3fe1b088218a72c61e613 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system';
 import { without } from 'lodash';
 import * as React from 'react';
@@ -26,7 +27,6 @@ import * as api from '../../../../api/permissions';
 import withAppStateContext, {
   WithAppStateContextProps,
 } from '../../../../app/components/app-state/withAppStateContext';
-import Suggestions from '../../../../components/embed-docs-modal/Suggestions';
 import AllHoldersList from '../../../../components/permissions/AllHoldersList';
 import { FilterOption } from '../../../../components/permissions/SearchForm';
 import { translate } from '../../../../helpers/l10n';
@@ -259,7 +259,6 @@ class PermissionsGlobalApp extends React.PureComponent<Props, State> {
     return (
       <LargeCenteredLayout id="project-permissions-page">
         <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-          <Suggestions suggestions="global_permissions" />
           <Helmet defer={false} title={translate('global_permissions.permission')} />
           <PageHeader />
           <AllHoldersList
index c42b8d6ba678be0ead55cb947cd8b6a61aac8b07..781cd0bbb17b9c7ccf413496503365ec18c0b1e5 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import {
   LargeCenteredLayout,
@@ -28,7 +29,6 @@ import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../../helpers/l10n';
 import { MeasureHistory, ParsedAnalysis } from '../../../types/project-activity';
 import { Component, Metric } from '../../../types/types';
@@ -69,7 +69,6 @@ export default function ProjectActivityAppRenderer(props: Props) {
   const canDeleteAnalyses = configuration?.showHistory;
   return (
     <main className="sw-p-5" id="project-activity">
-      <Suggestions suggestions="project_activity" />
       <Helmet defer={false} title={translate('project_activity.page')} />
 
       <A11ySkipTarget anchor="activity_main" />
index a286a1ba5937500a03fbf63cabe8bda9a60b6aa7..c3eb54a28ab4e2e1546dde4a862fba70f476557e 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage } from 'design-system';
 import { debounce, findLast, maxBy, minBy, sortBy } from 'lodash';
 import * as React from 'react';
@@ -35,6 +36,7 @@ import {
 } from '../../../components/activity-graph/utils';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { CCT_SOFTWARE_QUALITY_METRICS } from '../../../helpers/constants';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import {
   GraphType,
@@ -229,10 +231,7 @@ export default class ProjectActivityGraphs extends React.PureComponent<Props, St
             tagName="div"
             values={{
               learn_more: (
-                <DocumentationLink
-                  className="sw-whitespace-nowrap"
-                  to="/user-guide/clean-code/code-analysis/"
-                >
+                <DocumentationLink className="sw-whitespace-nowrap" to={DocLink.CodeAnalysis}>
                   {translate('learn_more')}
                 </DocumentationLink>
               ),
index e57ba4a2d10b262c3602b352c7187ea170c55990..e2965ad022f3d29df73f6492362ecb503cdb9913 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, FlagMessage, Modal } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { useSetMainBranchMutation } from '../../../queries/branch';
 import { Branch } from '../../../types/branch-like';
@@ -70,7 +72,7 @@ export default function SetAsMainBranchModal(props: SetAsMainBranchModalProps) {
               id="project_branch_pull_request.branch.main_branch.learn_more"
               values={{
                 documentation: (
-                  <DocumentationLink to="/analyzing-source-code/branches/branch-analysis/#main-branch">
+                  <DocumentationLink to={DocLink.MainBranchAnalysis}>
                     {translate('documentation')}
                   </DocumentationLink>
                 ),
index 24729625d74edf9270ee8d3fa10a4b0389aabb85..bcac8e01fc5823887ad2dd6707343a32735bff84 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   BasicSeparator,
   DownloadButton,
@@ -34,6 +35,7 @@ import { getBranches } from '../../../api/branches';
 import { getRegulatoryReportUrl } from '../../../api/regulatory-report';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { getBranchLikeDisplayName, getBranchLikeKey } from '../../../helpers/branch-like';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { LabelValueSelectOption } from '../../../helpers/search';
 import { BranchLike } from '../../../types/branch-like';
@@ -140,7 +142,7 @@ export default function RegulatoryReport({ component, branchLike }: Props) {
                 defaultMessage={translate('regulatory_page.available_branches_info.more_info')}
                 values={{
                   doc_link: (
-                    <DocumentationLink to="/analyzing-source-code/branches/branch-analysis/#inactive-branches">
+                    <DocumentationLink to={DocLink.InactiveBranches}>
                       {translate('regulatory_page.available_branches_info.more_info.doc_link')}
                     </DocumentationLink>
                   ),
index c8be13dc9730079903b5ae18fda5fbe1b6d418fb..bd9d0cc49c23f35d0dd4040399cc95cee736d523 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { HeadingDark, Link, Title } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
@@ -29,7 +31,7 @@ export interface AppHeaderProps {
 
 export default function AppHeader(props: AppHeaderProps) {
   const { canAdmin } = props;
-  const toUrl = useDocUrl('/project-administration/clean-as-you-code-settings/defining-new-code/');
+  const toUrl = useDocUrl(DocLink.NewCodeDefinition);
 
   return (
     <header className="sw-mt-8 sw-mb-4">
index 8905321c0c8018717c5f7f086b5e22ca79b78669..1d56019cc441b2a3c2e78bf8615eca61856fe12c 100644 (file)
@@ -29,6 +29,7 @@ import withAvailableFeatures, {
 import withComponentContext from '../../../app/components/componentContext/withComponentContext';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { sortBranches } from '../../../helpers/branch-like';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import {
   DEFAULT_NEW_CODE_DEFINITION_TYPE,
@@ -192,7 +193,7 @@ function ProjectNewCodeDefinitionApp(props: Readonly<ProjectNewCodeDefinitionApp
 
   return (
     <LargeCenteredLayout id="new-code-rules-page">
-      <Suggestions suggestions="project_baseline" />
+      <Suggestions suggestion={DocLink.NewCodeDefinition} />
 
       <Helmet defer={false} title={translate('project_baseline.page')} />
 
index cafa4b943a94393ba268e4b9f24e5e639eec8632..50528c55e9bdfc59e2e85bdace4c992a40e5150e 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonPrimary,
   FlagMessage,
@@ -39,6 +40,7 @@ import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
 import DisableableSelectOption from '../../components/common/DisableableSelectOption';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { isDiffMetric } from '../../helpers/measures';
 import { LabelValueSelectOption } from '../../helpers/search';
@@ -127,7 +129,7 @@ export default function ProjectQualityGateAppRenderer(props: ProjectQualityGateA
   return (
     <LargeCenteredLayout id="project-quality-gate">
       <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-        <Suggestions suggestions="project_quality_gate" />
+        <Suggestions suggestion={DocLink.CaYC} />
         <Helmet defer={false} title={translate('project_quality_gate.page')} />
         <A11ySkipTarget anchor="qg_main" />
 
index 42a80d32cb1e4d1f8358302b0886ee6b93fdc955..c256af2ee11aad943ea356134d1d3e194b31c17a 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ActionCell,
   ButtonPrimary,
@@ -40,6 +41,7 @@ import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
 import { Profile } from '../../api/quality-profiles';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { getRulesUrl } from '../../helpers/urls';
 import { Component } from '../../types/types';
@@ -91,7 +93,7 @@ export default function ProjectQualityProfilesAppRenderer(
   return (
     <LargeCenteredLayout id="project-quality-profiles">
       <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-        <Suggestions suggestions="project_quality_profiles" />
+        <Suggestions suggestion={DocLink.InstanceAdminQualityProfiles} />
         <Helmet defer={false} title={translate('project_quality_profiles.page')} />
         <A11ySkipTarget anchor="profiles_main" />
 
index 5da6829970f67dc006c116506cff65df1af046cc..18518ea0133dbfd7cb16451848f04aff97c855d3 100644 (file)
@@ -34,13 +34,11 @@ import { useSearchParams } from 'react-router-dom';
 import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
-import { MetricKey } from '~sonar-aligned/types/metrics';
 import { Location, RawQuery, Router } from '~sonar-aligned/types/router';
 import { searchProjects } from '../../../api/components';
 import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
 import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
 import ScreenPositionHelper from '../../../components/common/ScreenPositionHelper';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import '../../../components/search-navigator.css';
 import handleRequiredAuthentication from '../../../helpers/handleRequiredAuthentication';
 import { translate } from '../../../helpers/l10n';
@@ -307,7 +305,6 @@ export class AllProjects extends React.PureComponent<Props, State> {
   render() {
     return (
       <StyledWrapper id="projects-page">
-        <Suggestions suggestions={MetricKey.projects} />
         <Helmet defer={false} title={translate('projects.page')} />
 
         <h1 className="sw-sr-only">{translate('projects.page')}</h1>
index aa3412d0a134dcd6bea7fb106ec41de072a66e14..8447e0d8daed0b002648e4acffae836e034ec737 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system';
 import { debounce, uniq } from 'lodash';
 import * as React from 'react';
@@ -31,7 +32,6 @@ import {
 import { getValue } from '../../api/settings';
 import withCurrentUserContext from '../../app/components/current-user/withCurrentUserContext';
 import ListFooter from '../../components/controls/ListFooter';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { toShortISO8601String } from '../../helpers/dates';
 import { translate } from '../../helpers/l10n';
 import { hasGlobalPermission } from '../../helpers/users';
@@ -205,7 +205,6 @@ class ProjectManagementApp extends React.PureComponent<Props, State> {
     return (
       <LargeCenteredLayout as="main" id="projects-management-page">
         <PageContentFontWrapper className="sw-body-sm sw-my-8">
-          <Suggestions suggestions="projects_management" />
           <Helmet defer={false} title={translate('projects_management')} />
 
           <Header
index 020f38b8e9527220ff9f58706f1da302040c49e8..cb7f7bf5492b7cabee09a8b934d281507266636e 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { withTheme } from '@emotion/react';
 import styled from '@emotion/styled';
 import {
@@ -35,6 +36,7 @@ import { Helmet } from 'react-helmet-async';
 import { useNavigate, useParams } from 'react-router-dom';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import '../../../components/search-navigator.css';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getQualityGateUrl } from '../../../helpers/urls';
 import { useQualityGatesQuery } from '../../../queries/quality-gates';
@@ -84,7 +86,7 @@ export default function App() {
           )}
         />
         <div className="sw-grid sw-gap-x-12 sw-gap-y-6 sw-grid-cols-12 sw-w-full">
-          <Suggestions suggestions="quality_gates" />
+          <Suggestions suggestion={DocLink.CaYC} />
 
           <StyledContentWrapper
             className="sw-col-span-3 sw-px-4 sw-py-6 sw-border-y-0"
index 0ea24e58a14450edcc91a46431cb6b6dff630824..5ccb7aad5a53a4ccdf2d72599906ded9bb3c5b36 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { SpotlightTour, SpotlightTourStep } from 'design-system';
 import React from 'react';
 import { dismissNotice } from '../../../api/users';
 import { CurrentUserContext } from '../../../app/components/current-user/CurrentUserContext';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { QualityGate } from '../../../types/types';
 import { NoticeType } from '../../../types/users';
@@ -65,7 +67,7 @@ export default function CaYCConditionsSimplificationGuide({ qualityGate }: Props
           <p className="sw-mb-4">
             {translate('quality_gates.cayc.condition_simplification_tour.page_3.content1')}
           </p>
-          <DocumentationLink to="/user-guide/issues/#resolutions">
+          <DocumentationLink to={DocLink.IssueResolutions}>
             {translate('quality_gates.cayc.condition_simplification_tour.page_3.content2')}
           </DocumentationLink>
         </>
index c86aa008d71442b9c12552b8189dd00399ce3d7d..7ef1a49af76d719828c0846aed65faf7b56008d5 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   CardWithPrimaryBackground,
   CheckIcon,
@@ -26,6 +27,7 @@ import {
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { OPTIMIZED_CAYC_CONDITIONS } from '../utils';
 import QGRecommendedIcon from './QGRecommendedIcon';
@@ -45,7 +47,7 @@ export default function CaycCompliantBanner() {
           id="quality_gates.cayc.banner.description1"
           values={{
             cayc_link: (
-              <DocumentationLink to="/user-guide/clean-as-you-code/">
+              <DocumentationLink to={DocLink.CaYC}>
                 {translate('quality_gates.cayc')}
               </DocumentationLink>
             ),
index 49fc4f43c04d7e6a9e7ccb2ba8402457077d2c02..68532aff7e57f760f48a11de7a1474a7b2791a83 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, CardWithPrimaryBackground, SubHeadingHighlight } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import ModalButton from '../../../components/controls/ModalButton';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -48,7 +50,7 @@ export default function CaycNonCompliantBanner({ renderCaycModal, isOptimizing }
           }
           values={{
             cayc_link: (
-              <DocumentationLink to="/user-guide/clean-as-you-code/">
+              <DocumentationLink to={DocLink.CaYC}>
                 {translate('quality_gates.cayc')}
               </DocumentationLink>
             ),
index 40f4988504a89694025582b0dbc133e27468ab02..cc5e8ba28f1ca08f73f03867a25825f59f54ed98 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, Link, Modal, SubHeading, Title } from 'design-system';
 import { sortBy } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { useFixQualityGateMutation } from '../../../queries/quality-gates';
@@ -54,7 +56,7 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
     (condition) => metrics[condition.metric]?.name,
   );
 
-  const getDocUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.CaYC);
 
   const updateCaycQualityGate = React.useCallback(async () => {
     await fixQualityGate({ weakConditions, missingConditions });
@@ -71,11 +73,7 @@ export default function CaycReviewUpdateConditionsModal(props: Readonly<Props>)
               : 'quality_gates.cayc.review_update_modal.description1'
           }
           values={{
-            cayc_link: (
-              <Link to={getDocUrl('/user-guide/clean-as-you-code/')}>
-                {translate('quality_gates.cayc')}
-              </Link>
-            ),
+            cayc_link: <Link to={docUrl}>{translate('quality_gates.cayc')}</Link>,
           }}
         />
       </SubHeading>
index 2db45668ea6ee5ca6316621eaa524ce16ba1340d..dfc691dc57a3fee530e37472031343a2ff00e02f 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonSecondary,
   FlagMessage,
@@ -39,6 +40,7 @@ import { useAvailableFeatures } from '../../../app/components/available-features
 import { useMetrics } from '../../../app/components/metrics/withMetricsContext';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import ModalButton, { ModalProps } from '../../../components/controls/ModalButton';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
 import { Feature } from '../../../types/features';
@@ -119,7 +121,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
     [metrics, qualityGate],
   );
 
-  const getDocUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.CaYC);
   const isCompliantCustomQualityGate =
     qualityGate.caycStatus !== CaycStatus.NonCompliant && !qualityGate.isBuiltIn;
   const isOptimizing = isCompliantCustomQualityGate && !isQualityGateOptimized(qualityGate);
@@ -157,7 +159,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               id="quality_gates.is_built_in.cayc.description"
               values={{
                 link: (
-                  <DocumentationLink to="/user-guide/clean-as-you-code/">
+                  <DocumentationLink to={DocLink.CaYC}>
                     {translate('clean_as_you_code')}
                   </DocumentationLink>
                 ),
@@ -186,7 +188,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               content={translate('quality_gates.conditions.help')}
               links={[
                 {
-                  href: '/user-guide/clean-as-you-code/',
+                  href: DocLink.CaYC,
                   label: translate('quality_gates.conditions.help.link'),
                 },
               ]}
@@ -311,11 +313,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               id="quality_gates.cayc_unfollow.description"
               defaultMessage={translate('quality_gates.cayc_unfollow.description')}
               values={{
-                cayc_link: (
-                  <Link to={getDocUrl('/user-guide/clean-as-you-code/')}>
-                    {translate('quality_gates.cayc')}
-                  </Link>
-                ),
+                cayc_link: <Link to={docUrl}>{translate('quality_gates.cayc')}</Link>,
               }}
             />
           </SubHeading>
index 54458ab50d544aa69d9b0ea44269c0c4d76049b0..dd33243d83b4e68b03b8f1d6cf89745e2cdf1946 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, HelperHintIcon, Title } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import ModalButton, { ModalProps } from '../../../components/controls/ModalButton';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import CreateQualityGateForm from './CreateQualityGateForm';
 
@@ -59,7 +61,7 @@ export default function ListHeader({ canCreate }: Readonly<Props>) {
           content={translate('quality_gates.help')}
           links={[
             {
-              href: '/user-guide/quality-gates/',
+              href: DocLink.QualityGates,
               label: translate('learn_more'),
             },
           ]}
index 35937d20772efbeda7658071b79ba53e58f08762..76231c544ccba7378069b2a8a24777111d4a5080 100644 (file)
@@ -24,6 +24,7 @@ import { Outlet } from 'react-router-dom';
 import { Actions, getExporters, searchQualityProfiles } from '../../../api/quality-profiles';
 import withLanguagesContext from '../../../app/components/languages/withLanguagesContext';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Languages } from '../../../types/languages';
 import { QualityProfilesContextProps } from '../qualityProfilesContext';
@@ -109,7 +110,7 @@ export class QualityProfilesApp extends React.PureComponent<Props, State> {
   render() {
     return (
       <LargeCenteredLayout className="sw-my-8">
-        <Suggestions suggestions="quality_profiles" />
+        <Suggestions suggestion={DocLink.InstanceAdminQualityProfiles} />
         <Helmet defer={false} title={translate('quality_profiles.page')} />
 
         {this.renderChild()}
index 6edfcedc602de8bd3cf805aec3b33b8006c562e8..46746dd69a234096eb8347feefb53a1257f1c698 100644 (file)
@@ -22,6 +22,7 @@ import * as React from 'react';
 import { useIntl } from 'react-intl';
 import { useLocation, useRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { Actions } from '../../../api/quality-profiles';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 import { Profile } from '../types';
@@ -41,7 +42,7 @@ export default function PageHeader(props: Readonly<Props>) {
   const intl = useIntl();
   const location = useLocation();
   const router = useRouter();
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.InstanceAdminQualityProfiles);
 
   const [modal, setModal] = React.useState<'' | 'createProfile' | 'restoreProfile'>('');
 
@@ -63,7 +64,7 @@ export default function PageHeader(props: Readonly<Props>) {
         <div className="sw-body-sm">
           {intl.formatMessage({ id: 'quality_profiles.intro' })}
 
-          <Link className="sw-ml-2" to={docUrl('/instance-administration/quality-profiles/')}>
+          <Link className="sw-ml-2" to={docUrl}>
             {intl.formatMessage({ id: 'learn_more' })}
           </Link>
         </div>
index a8abe63617b14c64fdb27671e73c59f5e5cd5393..cfb76f48202766cab8eee3a715338a88b0d60f44 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { withTheme } from '@emotion/react';
 import styled from '@emotion/styled';
 import {
@@ -35,7 +36,6 @@ import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import { isBranch } from '~sonar-aligned/helpers/branch-like';
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import { MetricKey } from '~sonar-aligned/types/metrics';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../helpers/l10n';
 import useFollowScroll from '../../hooks/useFollowScroll';
 import { BranchLike } from '../../types/branch-like';
@@ -115,8 +115,6 @@ export default function SecurityHotspotsAppRenderer(props: SecurityHotspotsAppRe
 
   return (
     <>
-      <Suggestions suggestions={MetricKey.security_hotspots} />
-
       <Helmet title={translate('hotspots.page')} />
 
       <A11ySkipTarget anchor="security_hotspots_main" />
index 8a989fae4b1e5ca560c36e6d34fa97d2065a6cf8..2becfc24363809e228dc047734c1c75891a0b16f 100644 (file)
@@ -22,6 +22,7 @@ import { Note } from 'design-system';
 import * as React from 'react';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import { Image } from '../../../components/common/Image';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 
 export interface EmptyHotspotsPageProps {
@@ -59,7 +60,7 @@ export default function EmptyHotspotsPage(props: EmptyHotspotsPageProps) {
         {translate(`hotspots.${translationRoot}.description`)}
       </Note>
       {!(filtered || isStaticListOfHotspots) && (
-        <DocumentationLink className="sw-mt-4" to="/user-guide/security-hotspots/">
+        <DocumentationLink className="sw-mt-4" to={DocLink.SecurityHotspots}>
           {translate('hotspots.learn_more')}
         </DocumentationLink>
       )}
index 48accb664f178247bfeed03b15c522b315062c2c..a2531185977b3e94c9b77731b2cd81fa3654451d 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
+import { Link } from 'design-system';
 import * as React from 'react';
-import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
+import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
 export function HotspotDisabledFilterTooltip() {
+  const docUrl = useDocUrl(DocLink.InstanceAdminReindexation);
+
   return (
     <div className="sw-body-sm sw-w-[190px]">
       <p>
@@ -30,7 +35,7 @@ export function HotspotDisabledFilterTooltip() {
       </p>
       <hr className="sw-mx-0 sw-my-3 sw-p-0 sw-w-full" />
       <span className="sw-body-sm-highlight">{translate('indexation.learn_more')}</span>
-      <DocumentationLink
+      <Link
         className="sw-ml-1"
         onMouseDown={(e) => {
           // This tooltip content is rendered in the context of a <Dropdown>, and <DropdownToggler>
@@ -38,10 +43,10 @@ export function HotspotDisabledFilterTooltip() {
           // this link. We preventDefault() to avoid this behavior.
           e.preventDefault();
         }}
-        to="/instance-administration/reindexing/"
+        to={docUrl}
       >
         {translate('indexation.reindexing')}
-      </DocumentationLink>
+      </Link>
     </div>
   );
 }
index 47fe27f2bf1ca639944c5eb0b7a01d39f3a07b70..f60b393aa826c679046c5a65f241a20186c70b48 100644 (file)
@@ -22,6 +22,7 @@ import styled from '@emotion/styled';
 import { LightLabel } from 'design-system';
 import * as React from 'react';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { AdditionalCategoryComponentProps } from './AdditionalCategories';
 import CategoryDefinitionsList from './CategoryDefinitionsList';
@@ -46,7 +47,7 @@ export function AnalysisScope(props: AdditionalCategoryComponentProps) {
         <LightLabel>{translate('settings.analysis_scope.wildcards.single_char')}</LightLabel>
 
         <div className="sw-col-span-2">
-          <DocumentationLink to="/project-administration/analysis-scope/">
+          <DocumentationLink to={DocLink.AnalysisScope}>
             {translate('learn_more')}
           </DocumentationLink>
         </div>
index 77f8b8ef96e369f3cee83adcf6bb65e850d658af..a574b35d2e3f77c6d93f1c36a3a380896bee59b0 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Spinner } from '@sonarsource/echoes-react';
 import classNames from 'classnames';
 import { ButtonPrimary, ButtonSecondary } from 'design-system';
@@ -26,6 +27,7 @@ import DocumentationLink from '../../../components/common/DocumentationLink';
 import NewCodeDefinitionDaysOption from '../../../components/new-code-definition/NewCodeDefinitionDaysOption';
 import NewCodeDefinitionPreviousVersionOption from '../../../components/new-code-definition/NewCodeDefinitionPreviousVersionOption';
 import { NewCodeDefinitionLevels } from '../../../components/new-code-definition/utils';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import {
   getNumberOfDaysDefaultValue,
@@ -102,7 +104,7 @@ export default function NewCodeDefinition() {
                         id="settings.new_code_period.description3"
                         values={{
                           link: (
-                            <DocumentationLink to="/project-administration/clean-as-you-code-settings/defining-new-code/">
+                            <DocumentationLink to={DocLink.NewCodeDefinition}>
                               {translate('settings.new_code_period.description3.link')}
                             </DocumentationLink>
                           ),
index b93fae4b81929eebc52bc4ec3f639e82f321161d..361dd3306a8abc2dab6fa1d48bebbdf1105b456f 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import { LargeCenteredLayout, PageContentFontWrapper, themeBorder } from 'design-system';
 import { uniqBy } from 'lodash';
@@ -24,7 +25,6 @@ import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { Location } from '~sonar-aligned/types/router';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../../helpers/l10n';
 import { ExtendedSettingDefinition } from '../../../types/settings';
 import { Component } from '../../../types/types';
@@ -70,7 +70,6 @@ function SettingsAppRenderer(props: Readonly<SettingsAppRendererProps>) {
 
   return (
     <LargeCenteredLayout id="settings-page">
-      <Suggestions suggestions="settings" />
       <Helmet defer={false} title={translate('settings.page')} />
 
       <PageContentFontWrapper className="sw-my-8">
index 9b54225ab2f4baf78e4d99a8206db6cbe3b5e184..f9aa868d3d0d9dc2c69a3c62c23122a9bd3977d2 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   BasicSeparator,
   ButtonSecondary,
@@ -32,7 +33,8 @@ import { FormattedMessage } from 'react-intl';
 import HelpTooltip from '~sonar-aligned/components/controls/HelpTooltip';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
 import Tooltip from '../../../../components/controls/Tooltip';
-import { ALM_DOCUMENTATION_PATHS, IMPORT_COMPATIBLE_ALMS } from '../../../../helpers/constants';
+import { IMPORT_COMPATIBLE_ALMS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { getEdition, getEditionUrl } from '../../../../helpers/editions';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import {
@@ -232,7 +234,7 @@ export default function AlmBindingDefinitionBox(props: AlmBindingDefinitionBoxPr
                     )}
                     values={{
                       link: (
-                        <DocumentationLink to={ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]}>
+                        <DocumentationLink to={DocLink.AlmGitHubIntegration}>
                           {translate('learn_more')}
                         </DocumentationLink>
                       ),
index 6d714459fd6196362845a045e6f09bc13af896ac..0d0429fd133ac449b0a47bfc9936452b003c0789 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonSecondary,
   FlagMessage,
@@ -27,6 +28,7 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import { AlmBindingDefinitionBase } from '../../../../types/alm-settings';
@@ -65,7 +67,7 @@ export function AlmBindingDefinitionFormField<B extends AlmBindingDefinitionBase
   } = props;
   const [showField, setShowField] = React.useState(!overwriteOnly);
 
-  const toStatic = useDocUrl('/instance-administration/security/#settings-encryption');
+  const toStatic = useDocUrl(DocLink.InstanceAdminEncryption);
 
   return (
     <FormField
index d80d0f8d5d8ed4137b3330380761b2240f1285bf..6d4c3ae9c4f46d7cb69290519d289df7e5f78da4 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys, AzureBindingDefinition } from '../../../../types/alm-settings';
+import { AzureBindingDefinition } from '../../../../types/alm-settings';
 import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
 
 export interface AzureFormProps {
@@ -33,7 +34,7 @@ export interface AzureFormProps {
 
 export default function AzureForm(props: AzureFormProps) {
   const { formData, onFieldChange } = props;
-  const toStatic = useDocUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure]);
+  const toStatic = useDocUrl(DocLink.AlmAzureIntegration);
   return (
     <>
       <AlmBindingDefinitionFormField
index aa1e5d75ea526aaba26d4520e144066efeb44b8d..b24bedb37480e1dc75882bb3274f1628f4f34bcb 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
-import { useDocUrl } from '../../../../helpers/docs';
+import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys, BitbucketCloudBindingDefinition } from '../../../../types/alm-settings';
+import { BitbucketCloudBindingDefinition } from '../../../../types/alm-settings';
 import { BITBUCKET_CLOUD_WORKSPACE_ID_FORMAT } from '../../constants';
 import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
 
@@ -38,8 +39,6 @@ export default function BitbucketCloudForm(props: BitbucketCloudFormProps) {
     formData.workspace && !BITBUCKET_CLOUD_WORKSPACE_ID_FORMAT.test(formData.workspace),
   );
 
-  const toStatic = useDocUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketCloud]);
-
   return (
     <>
       <FlagMessage variant="info" className="sw-mb-8">
@@ -57,7 +56,11 @@ export default function BitbucketCloudForm(props: BitbucketCloudFormProps) {
                 </Link>
               ),
               permission: <strong>Pull Requests: Read</strong>,
-              doc_link: <Link to={toStatic}>{translate('learn_more')}</Link>,
+              doc_link: (
+                <DocumentationLink to={DocLink.AlmBitBucketCloudIntegration}>
+                  {translate('learn_more')}
+                </DocumentationLink>
+              ),
             }}
           />
         </div>
index f5c7587793fcb5a5507ec5543271a84ceb26545b..06d1221029b73ed56352fdd7bc50e2b9dd7f845e 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys, BitbucketServerBindingDefinition } from '../../../../types/alm-settings';
+import { BitbucketServerBindingDefinition } from '../../../../types/alm-settings';
 import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
 
 export interface BitbucketServerFormProps {
@@ -33,7 +34,7 @@ export interface BitbucketServerFormProps {
 
 export default function BitbucketServerForm(props: BitbucketServerFormProps) {
   const { formData } = props;
-  const toStatic = useDocUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.BitbucketServer]);
+  const toStatic = useDocUrl(DocLink.AlmBitBucketServerIntegration);
   return (
     <>
       <AlmBindingDefinitionFormField
index e48a6271841e78136797e49932eddfd048c3a17e..bced3853838aeefc3e6ed540ad29e65716626822 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys, GithubBindingDefinition } from '../../../../types/alm-settings';
+import { GithubBindingDefinition } from '../../../../types/alm-settings';
 import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
 
 export interface GithubFormProps {
@@ -33,7 +34,7 @@ export interface GithubFormProps {
 
 export default function GithubForm(props: GithubFormProps) {
   const { formData, onFieldChange } = props;
-  const toStatic = useDocUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.GitHub]);
+  const toStatic = useDocUrl(DocLink.AlmGitHubIntegration);
   return (
     <>
       <FlagMessage variant="info" className="sw-mb-8">
index 0cec69dece7c4b4a9980d939eec877346fbcc6cb..89793ac4df6b78e0ff84e5b822cd5f4b961566f5 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys, GitlabBindingDefinition } from '../../../../types/alm-settings';
+import { GitlabBindingDefinition } from '../../../../types/alm-settings';
 import { AlmBindingDefinitionFormField } from './AlmBindingDefinitionFormField';
 
 export interface GitlabFormProps {
@@ -33,7 +34,7 @@ export interface GitlabFormProps {
 
 export default function GitlabForm(props: GitlabFormProps) {
   const { formData, onFieldChange } = props;
-  const toStatic = useDocUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.GitLab]);
+  const toStatic = useDocUrl(DocLink.AlmGitLabIntegration);
   return (
     <>
       <AlmBindingDefinitionFormField
index 9ca2271d965a91aeddb8ffde57de773e5854990f..a227ebae99e17b769eb6091bf59c802dce575ede 100644 (file)
@@ -48,13 +48,6 @@ export type AuthenticationTabs =
   | AlmKeys.GitLab
   | AlmKeys.BitbucketServer;
 
-export const DOCUMENTATION_LINK_SUFFIXES = {
-  [SAML]: 'saml/overview',
-  [AlmKeys.GitHub]: 'github',
-  [AlmKeys.GitLab]: 'gitlab',
-  [AlmKeys.BitbucketServer]: 'bitbucket-cloud',
-};
-
 function renderDevOpsIcon(key: string) {
   return <Image alt={key} className="sw-mr-2" height={16} src={`/images/alm/${key}.svg`} />;
 }
index f41125fd67f282e09fafed66c1971f31b55e4da1..6eb8740005e90f104c1bc78cd46f325933e789c7 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonSecondary, Modal } from 'design-system';
 import { noop } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import { useToggleGithubProvisioningMutation } from '../../../../queries/identity-provider/github';
 import { useGetValueQuery, useResetSettingsMutation } from '../../../../queries/settings';
@@ -67,7 +69,7 @@ export default function AutoProvisioningConsent() {
           tagName="p"
           values={{
             documentation: (
-              <DocumentationLink to="/instance-administration/authentication/github/">
+              <DocumentationLink to={DocLink.AlmGitHubAuth}>
                 <FormattedMessage id="documentation" />
               </DocumentationLink>
             ),
index 6716e498fc3a5dca534a0aeb13be5bc5e57f777d..138817182b16fef37145a2b42f02ffa24db12db2 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import { useGetValueQuery } from '../../../../queries/settings';
 import { AlmKeys } from '../../../../types/alm-settings';
@@ -53,7 +55,7 @@ export default function BitbucketAuthenticationTab(props: Readonly<Props>) {
               id="settings.authentication.gitlab.configuration.insecure"
               values={{
                 documentation: (
-                  <DocumentationLink to="/instance-administration/authentication/bitbucket-cloud/#setting-your-authentication-settings-in-sonarqube">
+                  <DocumentationLink to={DocLink.AlmBitBucketCloudSettings}>
                     {translate('documentation')}
                   </DocumentationLink>
                 ),
@@ -69,7 +71,7 @@ export default function BitbucketAuthenticationTab(props: Readonly<Props>) {
             defaultMessage={translate('settings.authentication.help')}
             values={{
               link: (
-                <DocumentationLink to="/instance-administration/authentication/bitbucket-cloud/">
+                <DocumentationLink to={DocLink.AlmBitBucketCloudAuth}>
                   {translate('settings.authentication.help.link')}
                 </DocumentationLink>
               ),
index 6655ddaedb2463f719aaff192fac1b4f938310b3..45e72b066936d716cede0d827976de78891c65ff 100644 (file)
@@ -24,12 +24,13 @@ import { keyBy } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { AlmAuthDocLinkKeys } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import { useSaveValuesMutation } from '../../../../queries/settings';
 import { AlmKeys } from '../../../../types/alm-settings';
 import { ProvisioningType } from '../../../../types/provisioning';
 import { Dict, Provider } from '../../../../types/types';
-import { AuthenticationTabs, DOCUMENTATION_LINK_SUFFIXES } from './Authentication';
+import { AuthenticationTabs } from './Authentication';
 import AuthenticationFormField from './AuthenticationFormField';
 import ConfirmProvisioningModal from './ConfirmProvisioningModal';
 import { SettingValue } from './hook/useConfiguration';
@@ -125,9 +126,7 @@ export default function ConfigurationForm(props: Readonly<Props>) {
               id={`settings.authentication.${helpMessage}`}
               values={{
                 link: (
-                  <DocumentationLink
-                    to={`/instance-administration/authentication/${DOCUMENTATION_LINK_SUFFIXES[tab]}/`}
-                  >
+                  <DocumentationLink to={AlmAuthDocLinkKeys[tab]}>
                     {translate('settings.authentication.help.link')}
                   </DocumentationLink>
                 ),
index 829b9007e7eb403262449322d9b74b433e4dafb8..3ec7e17a066df7dcc8aa74dc3866f61fcf71acdd 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Spinner } from 'design-system';
 import { isEmpty, omitBy } from 'lodash';
 import React, { FormEvent, useContext } from 'react';
@@ -24,6 +25,7 @@ import { FormattedMessage } from 'react-intl';
 import GitLabSynchronisationWarning from '../../../../app/components/GitLabSynchronisationWarning';
 import { AvailableFeaturesContext } from '../../../../app/components/available-features/AvailableFeaturesContext';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import { useIdentityProviderQuery } from '../../../../queries/identity-provider/common';
 import {
@@ -32,12 +34,10 @@ import {
   useSyncWithGitLabNow,
   useUpdateGitLabConfigurationMutation,
 } from '../../../../queries/identity-provider/gitlab';
-import { AlmKeys } from '../../../../types/alm-settings';
 import { Feature } from '../../../../types/features';
 import { GitLabConfigurationUpdateBody, ProvisioningType } from '../../../../types/provisioning';
 import { DefinitionV2, SettingType } from '../../../../types/settings';
 import { Provider } from '../../../../types/types';
-import { DOCUMENTATION_LINK_SUFFIXES } from './Authentication';
 import AuthenticationFormField from './AuthenticationFormField';
 import ConfigurationDetails from './ConfigurationDetails';
 import ConfirmProvisioningModal from './ConfirmProvisioningModal';
@@ -273,11 +273,7 @@ export default function GitLabAuthenticationTab() {
                   id="settings.authentication.gitlab.provisioning_at_login.description"
                   values={{
                     documentation: (
-                      <DocumentationLink
-                        to={`/instance-administration/authentication/${
-                          DOCUMENTATION_LINK_SUFFIXES[AlmKeys.GitLab]
-                        }/#choosing-the-provisioning-method`}
-                      >
+                      <DocumentationLink to={DocLink.AlmGitLabAuthProvisioningMethod}>
                         {translate(`learn_more`)}
                       </DocumentationLink>
                     ),
@@ -323,7 +319,7 @@ export default function GitLabAuthenticationTab() {
                   )}
                   values={{
                     documentation: (
-                      <DocumentationLink to="/instance-administration/authentication/gitlab">
+                      <DocumentationLink to={DocLink.AlmGitLabAuth}>
                         {translate('documentation')}
                       </DocumentationLink>
                     ),
@@ -335,11 +331,7 @@ export default function GitLabAuthenticationTab() {
                   id="settings.authentication.gitlab.form.provisioning_with_gitlab.description"
                   values={{
                     documentation: (
-                      <DocumentationLink
-                        to={`/instance-administration/authentication/${
-                          DOCUMENTATION_LINK_SUFFIXES[AlmKeys.GitLab]
-                        }/#choosing-the-provisioning-method`}
-                      >
+                      <DocumentationLink to={DocLink.AlmGitLabAuthProvisioningMethod}>
                         {translate(`learn_more`)}
                       </DocumentationLink>
                     ),
index 41845a5b896dd04f428efed3379566ff8125ef53..b14f2999d8cefbe94e5f4cad431caf8cbadda504 100644 (file)
@@ -23,6 +23,7 @@ import { keyBy } from 'lodash';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import {
   useCreateGitLabConfigurationMutation,
@@ -30,7 +31,6 @@ import {
 } from '../../../../queries/identity-provider/gitlab';
 import { GitLabConfigurationCreateBody, GitlabConfiguration } from '../../../../types/provisioning';
 import { DefinitionV2, SettingType } from '../../../../types/settings';
-import { DOCUMENTATION_LINK_SUFFIXES } from './Authentication';
 import AuthenticationFormField from './AuthenticationFormField';
 
 interface Props {
@@ -149,9 +149,7 @@ export default function GitLabConfigurationForm(props: Readonly<Props>) {
             id="settings.authentication.help"
             values={{
               link: (
-                <DocumentationLink
-                  to={`/instance-administration/authentication/${DOCUMENTATION_LINK_SUFFIXES.gitlab}/`}
-                >
+                <DocumentationLink to={DocLink.AlmGitLabAuth}>
                   {translate('settings.authentication.help.link')}
                 </DocumentationLink>
               ),
index e9da422d772b2efa283aa34784f9ca3ec0e4acab..99b3caffb8d6b60c422396121099688d3627efb8 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonSecondary, FlagMessage, Highlight, Note, Spinner } from 'design-system';
 import React, { FormEvent, useState } from 'react';
 import { FormattedMessage } from 'react-intl';
 import GitHubSynchronisationWarning from '../../../../app/components/GitHubSynchronisationWarning';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
 import { useIdentityProviderQuery } from '../../../../queries/identity-provider/common';
 import {
@@ -32,7 +34,7 @@ import { AlmKeys } from '../../../../types/alm-settings';
 import { ProvisioningType } from '../../../../types/provisioning';
 import { ExtendedSettingDefinition } from '../../../../types/settings';
 import { Provider } from '../../../../types/types';
-import { AuthenticationTabs, DOCUMENTATION_LINK_SUFFIXES } from './Authentication';
+import { AuthenticationTabs } from './Authentication';
 import AuthenticationFormField from './AuthenticationFormField';
 import AutoProvisioningConsent from './AutoProvisionningConsent';
 import ConfigurationDetails from './ConfigurationDetails';
@@ -155,7 +157,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
                 defaultMessage={translate('settings.authentication.github.form.legacy_configured')}
                 values={{
                   documentation: (
-                    <DocumentationLink to="/instance-administration/authentication/github">
+                    <DocumentationLink to={DocLink.AlmGitHubAuth}>
                       {translate('settings.authentication.github.form.legacy_configured.link')}
                     </DocumentationLink>
                   ),
@@ -198,11 +200,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
                   id="settings.authentication.github.form.provisioning_at_login.description"
                   values={{
                     documentation: (
-                      <DocumentationLink
-                        to={`/instance-administration/authentication/${
-                          DOCUMENTATION_LINK_SUFFIXES[AlmKeys.GitHub]
-                        }/`}
-                      >
+                      <DocumentationLink to={DocLink.AlmGitHubAuth}>
                         {translate('learn_more')}
                       </DocumentationLink>
                     ),
@@ -239,7 +237,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
                   )}
                   values={{
                     documentation: (
-                      <DocumentationLink to="/instance-administration/authentication/github">
+                      <DocumentationLink to={DocLink.AlmGitHubAuth}>
                         {translate('documentation')}
                       </DocumentationLink>
                     ),
@@ -251,11 +249,7 @@ export default function GithubAuthenticationTab(props: GithubAuthenticationProps
                   id="settings.authentication.github.form.provisioning_with_github.description"
                   values={{
                     documentation: (
-                      <DocumentationLink
-                        to={`/instance-administration/authentication/${
-                          DOCUMENTATION_LINK_SUFFIXES[AlmKeys.GitHub]
-                        }/`}
-                      >
+                      <DocumentationLink to={DocLink.AlmGitHubAuth}>
                         {translate('learn_more')}
                       </DocumentationLink>
                     ),
index cb0c2b6c9eb9b13781836208892699cc1928cdbb..42550d1ab9d4144a81817b32e644771d5d9474a5 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonSecondary, Spinner } from 'design-system';
 import React, { FormEvent } from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
 import ConfirmModal from '../../../../components/controls/ConfirmModal';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import { useIdentityProviderQuery } from '../../../../queries/identity-provider/common';
 import { useToggleScimMutation } from '../../../../queries/identity-provider/scim';
@@ -167,7 +169,7 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) {
                   id="settings.authentication.saml.form.provisioning.disabled"
                   values={{
                     documentation: (
-                      <DocumentationLink to="/instance-administration/authentication/saml/scim/overview">
+                      <DocumentationLink to={DocLink.AlmSamlScimAuth}>
                         {translate('documentation')}
                       </DocumentationLink>
                     ),
@@ -192,7 +194,7 @@ export default function SamlAuthenticationTab(props: SamlAuthenticationProps) {
                       )}
                       values={{
                         documentation: (
-                          <DocumentationLink to="/instance-administration/authentication/saml/scim/overview">
+                          <DocumentationLink to={DocLink.AlmSamlScimAuth}>
                             {translate('documentation')}
                           </DocumentationLink>
                         ),
index 0e3fa7f923588f178c763e91a26b4f6d1dfe7269..80b4f8caeb573e5c22c17b3e7c5360ec11ec3436 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, InputField, Note, RequiredIcon, SubHeading, Switch } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
@@ -24,6 +25,7 @@ import withAvailableFeatures, {
   WithAvailableFeaturesProps,
 } from '../../../../app/components/available-features/withAvailableFeatures';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import { convertGithubApiUrlToLink, stripTrailingSlash } from '../../../../helpers/urls';
 import {
@@ -293,7 +295,7 @@ export function AlmSpecificForm(props: AlmSpecificFormProps) {
           help: true,
           helpParams: {
             doc_link: (
-              <DocumentationLink to="/project-administration/monorepos/">
+              <DocumentationLink to={DocLink.Monorepos}>
                 {translate('learn_more')}
               </DocumentationLink>
             ),
index f1c825781645daa536ca60a07234a25ef46a46ad..4617a15b86b925735d860e1e3b42cb968329c1f6 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonPrimary,
   ButtonSecondary,
@@ -30,6 +31,7 @@ import { useCallback, useState } from 'react';
 import { FormattedMessage } from 'react-intl';
 import { encryptValue } from '../../../api/settings';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -122,7 +124,7 @@ export default function EncryptionForm({ generateSecretKey }: Readonly<Props>) {
             id="encryption.form_note"
             values={{
               moreInformationLink: (
-                <DocumentationLink to="/instance-administration/security/">
+                <DocumentationLink to={DocLink.InstanceAdminSecurity}>
                   {translate('more_information')}
                 </DocumentationLink>
               ),
index b120142bb20d2005cfa52ce051d4ac00648b4f41..6d64b7ad4ad6e18b229195b4cf80b13acccb097a 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ButtonPrimary,
   ClipboardIconButton,
@@ -30,6 +31,7 @@ import * as React from 'react';
 import { useCallback, useState } from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 
 interface Props {
@@ -107,7 +109,7 @@ export default function GenerateSecretKeyForm({ secretKey, generateSecretKey }:
               id="encryption.secret_key_description"
               values={{
                 moreInformationLink: (
-                  <DocumentationLink to="/instance-administration/security/">
+                  <DocumentationLink to={DocLink.InstanceAdminSecurity}>
                     {translate('more_information')}
                   </DocumentationLink>
                 ),
index 664c36e0cb5a9c555c12c7e6801213ed12f3c235..0e901c5fc5049c2bd391f003cae5db4f78d38976 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { LargeCenteredLayout, PageContentFontWrapper } from 'design-system';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
@@ -24,7 +25,6 @@ import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { Location, Router } from '~sonar-aligned/types/router';
 import { getSystemInfo } from '../../../api/system';
 import UpdateNotification from '../../../app/components/update-notification/UpdateNotification';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../../helpers/l10n';
 import { SysInfoCluster, SysInfoStandalone } from '../../../types/types';
 import '../styles.css';
@@ -126,7 +126,6 @@ class SystemApp extends React.PureComponent<Props, State> {
     const { loading, sysInfoData } = this.state;
     return (
       <LargeCenteredLayout as="main">
-        <Suggestions suggestions="system_info" />
         <Helmet defer={false} title={translate('system_info.page')} />
         <PageContentFontWrapper className="sw-body-sm sw-pb-8">
           <div>
index 99693e98db42155f7ffac9f298eaf3c50cc42f79..1b4c87b33f5f9bb20bf26356b1d829b2798a9f28 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ButtonPrimary, FlagMessage, Link, Title } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 import { translate } from '../../helpers/l10n';
 import UserForm from './components/UserForm';
@@ -29,7 +31,7 @@ interface Props {
 }
 
 export default function Header(props: Props) {
-  const getDocUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.AuthOverview);
   const [openUserForm, setOpenUserForm] = React.useState(false);
 
   const { manageProvider } = props;
@@ -57,11 +59,7 @@ export default function Header(props: Props) {
                 id="users.page.managed_description"
                 values={{
                   provider: manageProvider,
-                  link: (
-                    <Link to={getDocUrl('/instance-administration/authentication/overview/')}>
-                      {translate('documentation')}
-                    </Link>
-                  ),
+                  link: <Link to={docUrl}>{translate('documentation')}</Link>,
                 }}
               />
             </span>
index c40d1ce5865404b5a4dbabf8a0dfaa73620309e1..713bcef1726a1731a1872180ff0fcbdf9ae7ab69 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { subDays, subSeconds } from 'date-fns';
 import {
   HelperHintIcon,
@@ -35,7 +36,6 @@ import GitHubSynchronisationWarning from '../../app/components/GitHubSynchronisa
 import GitLabSynchronisationWarning from '../../app/components/GitLabSynchronisationWarning';
 import ListFooter from '../../components/controls/ListFooter';
 import { ManagedFilter } from '../../components/controls/ManagedFilter';
-import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { now, toISO8601WithOffsetString } from '../../helpers/dates';
 import { translate } from '../../helpers/l10n';
 import { LabelValueSelectOption } from '../../helpers/search';
@@ -98,7 +98,6 @@ export default function UsersApp() {
   return (
     <LargeCenteredLayout as="main" id="users-page">
       <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-        <Suggestions suggestions="users" />
         <Helmet defer={false} title={translate('users.page')} />
         <Header manageProvider={manageProvider?.provider} />
         {manageProvider?.provider === Provider.Github && <GitHubSynchronisationWarning short />}
index c681a0dc0acfa5e4866eeb22f98c1c215497c837..e1d1c68417c5531bba2ba1a4c2d0f50d76fbd8e0 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   Checkbox,
   DangerButtonPrimary,
@@ -27,6 +28,7 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { useDeactivateUserMutation } from '../../../queries/users';
@@ -56,7 +58,7 @@ export default function DeactivateForm(props: Props) {
   };
 
   const header = translate('users.deactivate_user');
-  const docUrl = useDocUrl('/instance-administration/authentication/overview/');
+  const docUrl = useDocUrl(DocLink.AuthOverview);
 
   return (
     <Modal
index f61afe7235a11c192e7e9657a4fbcba4b4855255..6ee0e211f0587a7ab7bbd38197331963d8b641ef 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import {
   LAYOUT_FOOTER_HEIGHT,
@@ -33,7 +34,6 @@ import A11ySkipTarget from '~sonar-aligned/components/a11y/A11ySkipTarget';
 import { withRouter } from '~sonar-aligned/components/hoc/withRouter';
 import { Location, Router } from '~sonar-aligned/types/router';
 import { fetchWebApi } from '../../../api/web-api';
-import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../../helpers/l10n';
 import { WebApi } from '../../../types/types';
 import '../styles/web-api.css';
@@ -168,7 +168,6 @@ export class WebApiApp extends React.PureComponent<Props, State> {
     return (
       <LargeCenteredLayout>
         <PageContentFontWrapper className="sw-body-sm sw-w-full sw-flex">
-          <Suggestions suggestions="api_documentation" />
           <Helmet defer={false} title={translate('api_documentation.page')} />
           <div className="sw-w-full sw-flex">
             <NavContainer
index 50e723ebf89626c0de1c65c20b8376d4f8eec8df..3006544685665497146e2944ff3e575749111b4d 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { LargeCenteredLayout, PageContentFontWrapper, Spinner } from 'design-system';
 import * as React from 'react';
 import { useCallback, useEffect, useState } from 'react';
@@ -24,6 +25,7 @@ import { Helmet } from 'react-helmet-async';
 import { createWebhook, deleteWebhook, searchWebhooks, updateWebhook } from '../../../api/webhooks';
 import withComponentContext from '../../../app/components/componentContext/withComponentContext';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Component } from '../../../types/types';
 import { WebhookResponse } from '../../../types/webhook';
@@ -100,7 +102,7 @@ export function App({ component }: AppProps) {
   return (
     <LargeCenteredLayout id="project-webhooks">
       <PageContentFontWrapper className="sw-my-8 sw-body-sm">
-        <Suggestions suggestions="webhooks" />
+        <Suggestions suggestion={DocLink.Webhooks} />
         <Helmet defer={false} title={translate('webhooks.page')} />
         <PageHeader>
           <PageActions loading={loading} onCreate={handleCreate} webhooksCount={webhooks.length} />
index 672f76b8b8681d5354588e0b5b928bfb51a6eac0..61db225664d53d9f2bbd1d0dd0096087d3a0ea74 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link, Title } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
@@ -28,7 +30,7 @@ interface Props {
 }
 
 export default function PageHeader({ children }: Readonly<Props>) {
-  const toUrl = useDocUrl('/project-administration/webhooks/');
+  const toUrl = useDocUrl(DocLink.Webhooks);
 
   return (
     <header className="sw-mb-2 sw-flex sw-items-center sw-justify-between">
index cf5ba0114a209e57fc9f3b033db6ae1ff3ddb784..b6cdc6a26f8b125ffdd879a6f75ead2d79188ab4 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
-import { Link, LinkProps } from 'design-system';
+
+import { Link, LinkProps } from '@sonarsource/echoes-react';
 import * as React from 'react';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 
-type Props = Omit<LinkProps, 'to'> & { to: string; innerRef?: React.Ref<HTMLAnchorElement> };
+type Props = Omit<LinkProps, 'to'> & { to: DocLink; innerRef?: React.Ref<HTMLAnchorElement> };
 
 export default function DocumentationLink({ to, innerRef, ...props }: Props) {
   const toStatic = useDocUrl(to);
-  return <Link ref={innerRef} to={toStatic} target="_blank" {...props} />;
+
+  return <Link ref={innerRef} to={toStatic} {...props} />;
 }
index 0d8e07e44129b50fcddc35fd233f42b7c4204ab4..0ca48ab3ac70cc59f771c42146469cc337588cfa 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ItemLink, OpenNewTabIcon } from 'design-system';
 import * as React from 'react';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 
 interface Props {
-  to: string;
-  innerRef?: React.Ref<HTMLAnchorElement>;
   children: React.ReactNode;
+  innerRef?: React.Ref<HTMLAnchorElement>;
+  to: DocLink;
 }
 
 export function DocItemLink({ to, innerRef, children }: Props) {
index 8f613d698e52402713981d80b6f65715e98f92ba..152767937702135a3397c34c3fcfea867da93a62 100644 (file)
@@ -20,6 +20,7 @@
 
 import { ItemDivider, ItemHeader, ItemLink, OpenNewTabIcon } from 'design-system';
 import * as React from 'react';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { SuggestionLink } from '../../types/types';
 import { Image } from '../common/Image';
@@ -87,7 +88,7 @@ export function EmbedDocsPopup() {
       {suggestions.length !== 0 && (
         <Suggestions firstItemRef={firstItemRef} suggestions={suggestions} />
       )}
-      <DocItemLink innerRef={suggestions.length === 0 ? firstItemRef : undefined} to="/">
+      <DocItemLink innerRef={suggestions.length === 0 ? firstItemRef : undefined} to={DocLink.Root}>
         {translate('docs.documentation')}
       </DocItemLink>
       <ItemLink to="/web_api">{translate('api_documentation.page')}</ItemLink>
diff --git a/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json b/server/sonar-web/src/main/js/components/embed-docs-modal/EmbedDocsSuggestions.json
deleted file mode 100644 (file)
index 8901c50..0000000
+++ /dev/null
@@ -1,118 +0,0 @@
-{
-  "account": [],
-  "api_documentation": [],
-  "background_tasks": [
-    {
-      "link": "/analyzing-source-code/background-tasks/",
-      "text": "About Background Tasks"
-    }
-  ],
-  "code": [],
-  "coding_rules": [
-    {
-      "link": "/instance-administration/quality-profiles/",
-      "text": "Quality Profiles"
-    }
-  ],
-  "component_measures": [
-    {
-      "link": "/user-guide/clean-as-you-code/",
-      "text": "Clean as You Code"
-    },
-    {
-      "link": "/user-guide/metric-definitions/",
-      "text": "Metric Definitions"
-    }
-  ],
-  "global_permissions": [],
-  "issues": [],
-  "marketplace": [],
-  "overview": [
-    {
-      "link": "/analyzing-source-code/pull-request-analysis",
-      "text": "Enable Pull Request Decoration"
-    },
-    {
-      "link": "/analyzing-source-code/ci-integration/overview/",
-      "text": "Set up CI analysis"
-    },
-    {
-      "link": "/user-guide/clean-as-you-code/",
-      "text": "Clean as You Code"
-    },
-    {
-      "link": "/user-guide/sonarlint-connected-mode/",
-      "text": "SonarLint Connected Mode"
-    }
-  ],
-  "permission_templates": [],
-  "profiles": [
-    {
-      "link": "/instance-administration/quality-profiles/",
-      "text": "Quality Profiles"
-    }
-  ],
-  "project_activity": [],
-  "project_baseline": [
-    {
-      "link": "/project-administration/clean-as-you-code-settings/defining-new-code/",
-      "text": "Defining New Code"
-    }
-  ],
-  "project_quality_gate": [
-    {
-      "link": "/user-guide/clean-as-you-code/",
-      "text": "Clean as You Code"
-    }
-  ],
-  "project_quality_profiles": [
-    {
-      "link": "/instance-administration/quality-profiles/",
-      "text": "About Quality Profiles"
-    }
-  ],
-  "projects_management": [],
-  "projects": [],
-  "pull_requests": [
-    {
-      "link": "/user-guide/clean-as-you-code/",
-      "text": "Clean as You Code"
-    },
-    {
-      "link": "/analyzing-source-code/pull-request-analysis",
-      "text": "Analyzing Pull Requests"
-    },
-    {
-      "link": "/user-guide/sonarlint-connected-mode/",
-      "text": "SonarLint connected mode"
-    }
-  ],
-  "quality_gates": [
-    {
-      "link": "/user-guide/clean-as-you-code/",
-      "text": "Clean as You Code"
-    }
-  ],
-  "quality_profiles": [
-    {
-      "link": "/instance-administration/quality-profiles/",
-      "text": "Quality Profiles"
-    }
-  ],
-  "security_reports": [
-    {
-      "link": "/user-guide/security-reports/",
-      "text": "About Security Reports"
-    }
-  ],
-  "settings": [],
-  "system_info": [],
-  "user_groups": [],
-  "users": [],
-  "webhooks": [
-    {
-      "link": "/project-administration/webhooks/",
-      "text": "About Webhooks"
-    }
-  ]
-}
index 1fdad7082245e072bb90ed3fee115ebf18e9d24b..7a02556e3b99d299bf662a096a76cc118527c48a 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import * as React from 'react';
-import { SuggestionsContext } from './SuggestionsContext';
+import { DocSection, DocSectionKey, DocTitleKey } from '../../helpers/doc-links';
+import { isDefined } from '../../helpers/types';
+import { SuggestionsContext, SuggestionsContextShape } from './SuggestionsContext';
 
-interface Props {
-  suggestions: string;
-}
+type Props =
+  | {
+      suggestion: DocTitleKey;
+      suggestionGroup?: never;
+    }
+  | {
+      suggestion?: never;
+      suggestionGroup: DocSectionKey;
+    };
 
-export default function Suggestions({ suggestions }: Props) {
+export default function Suggestions({ suggestion, suggestionGroup }: Readonly<Props>) {
   return (
     <SuggestionsContext.Consumer>
       {({ addSuggestions, removeSuggestions }) => (
         <SuggestionsInner
           addSuggestions={addSuggestions}
           removeSuggestions={removeSuggestions}
-          suggestions={suggestions}
+          suggestion={suggestion}
+          suggestionGroup={suggestionGroup}
         />
       )}
     </SuggestionsContext.Consumer>
@@ -39,25 +49,31 @@ export default function Suggestions({ suggestions }: Props) {
 }
 
 interface SuggestionsInnerProps {
-  addSuggestions: (key: string) => void;
-  removeSuggestions: (key: string) => void;
-  suggestions: string;
+  addSuggestions: SuggestionsContextShape['addSuggestions'];
+  removeSuggestions: SuggestionsContextShape['removeSuggestions'];
+  suggestion: Props['suggestion'];
+  suggestionGroup: Props['suggestionGroup'];
 }
 
 class SuggestionsInner extends React.PureComponent<SuggestionsInnerProps> {
   componentDidMount() {
-    this.props.addSuggestions(this.props.suggestions);
+    this.props.addSuggestions(this.getSuggestionListFromProps());
   }
 
-  componentDidUpdate(prevProps: Props) {
-    if (prevProps.suggestions !== this.props.suggestions) {
-      this.props.removeSuggestions(this.props.suggestions);
-      this.props.addSuggestions(prevProps.suggestions);
-    }
+  componentWillUnmount() {
+    this.props.removeSuggestions(this.getSuggestionListFromProps());
   }
 
-  componentWillUnmount() {
-    this.props.removeSuggestions(this.props.suggestions);
+  getSuggestionListFromProps() {
+    const { suggestion, suggestionGroup } = this.props;
+
+    const suggestions: DocTitleKey[] = isDefined(suggestion) ? [suggestion] : [];
+
+    if (suggestionGroup) {
+      suggestions.push(...DocSection[suggestionGroup]);
+    }
+
+    return suggestions;
   }
 
   render() {
index 7dc73b62d7caffeb229fa2d0016c535aa5fb74b7..d71d4cef5c94099491e17901e61fc4619aaa4972 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { createContext } from 'react';
+import { DocTitleKey } from '../../helpers/doc-links';
 import { SuggestionLink } from '../../types/types';
 
-interface SuggestionsContextShape {
-  addSuggestions: (key: string) => void;
-  removeSuggestions: (key: string) => void;
+export interface SuggestionsContextShape {
+  addSuggestions: (keys: DocTitleKey[]) => void;
+  removeSuggestions: (keys: DocTitleKey[]) => void;
   suggestions: SuggestionLink[];
 }
 
index b09f8aefa9d4dd1d12f4ff753675d66d06323a8f..c0d680938c71280022fff55fe1618ec041b60d60 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import * as React from 'react';
-import { Dict, SuggestionLink } from '../../types/types';
-import suggestionsJson from './EmbedDocsSuggestions.json';
+import { DocTitle, DocTitleKey } from '../../helpers/doc-links';
+import { SuggestionLink } from '../../types/types';
 import { SuggestionsContext } from './SuggestionsContext';
 
-type SuggestionsJson = Dict<SuggestionLink[]>;
-
 interface State {
   suggestions: SuggestionLink[];
 }
 
 export default class SuggestionsProvider extends React.Component<React.PropsWithChildren, State> {
-  keys: string[] = [];
+  keys: Array<DocTitleKey> = [];
   state: State = { suggestions: [] };
 
   fetchSuggestions = () => {
-    const jsonList = suggestionsJson as SuggestionsJson;
     let suggestions: SuggestionLink[] = [];
+
     this.keys.forEach((key) => {
-      if (jsonList[key]) {
-        suggestions = [...jsonList[key], ...suggestions];
-      }
+      suggestions = [{ link: key, text: DocTitle[key] }, ...suggestions];
     });
 
     this.setState({ suggestions });
   };
 
-  addSuggestions = (newKey: string) => {
-    this.keys = [...this.keys, newKey];
+  addSuggestions = (newKeys: DocTitleKey[]) => {
+    newKeys.forEach((newKey) => {
+      if (!this.keys.includes(newKey)) {
+        this.keys = [...this.keys, newKey];
+      }
+    });
+
     this.fetchSuggestions();
   };
 
-  removeSuggestions = (oldKey: string) => {
-    this.keys = this.keys.filter((key) => key !== oldKey);
+  removeSuggestions = (oldKeys: DocTitleKey[]) => {
+    oldKeys.forEach((oldKey) => {
+      this.keys = this.keys.filter((key) => key !== oldKey);
+    });
+
     this.fetchSuggestions();
   };
 
index 6b7c48e73a0c7749f3e65bbbe23bda3dbab47374..ef09bf7b4b0ab35d0497bee2b48cf803afe8a5a1 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { screen } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
+import { DocLink, DocTitleKey } from '../../../helpers/doc-links';
 import { renderComponent } from '../../../helpers/testReactTestingUtils';
 import EmbedDocsPopupHelper from '../EmbedDocsPopupHelper';
 import Suggestions from '../Suggestions';
@@ -60,10 +62,10 @@ it('should be able to render with suggestions and remove them', async () => {
 
 function renderEmbedDocsPopup() {
   function Test() {
-    const [suggestions, setSuggestions] = React.useState<string[]>(['account']);
+    const [suggestions, setSuggestions] = React.useState<DocTitleKey[]>([]);
 
     const addSuggestion = () => {
-      setSuggestions([...suggestions, 'background_tasks']);
+      setSuggestions([...suggestions, DocLink.BackgroundTasks]);
     };
 
     return (
@@ -81,7 +83,7 @@ function renderEmbedDocsPopup() {
         </button>
         <EmbedDocsPopupHelper />
         {suggestions.map((suggestion) => (
-          <Suggestions key={suggestion} suggestions={suggestion} />
+          <Suggestions key={suggestion} suggestion={suggestion} />
         ))}
       </SuggestionsProvider>
     );
index 9dff3ce2bdcf88300601fd19ebd0ff92af836d26..8fd429cd4244417162d6b305720bc4053ccd1444 100644 (file)
@@ -21,6 +21,7 @@
 import { IconProps, TextSubdued } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { IssueSeverity as IssueSeverityType } from '../../../types/issues';
 import { Issue } from '../../../types/types';
@@ -37,7 +38,7 @@ export default function IssueSeverity({ issue, ...iconProps }: Readonly<Props>)
       content={<DeprecatedFieldTooltip field="severity" />}
       links={[
         {
-          href: '/user-guide/issues',
+          href: DocLink.Issues,
           label: translate('learn_more'),
         },
       ]}
index 892d6c370252bfc9be7350a6fd3db2c6bf128070..4932bb33cc194c799f1bfcc77373b61aad950f7b 100644 (file)
@@ -21,6 +21,7 @@
 import { IconProps, TextSubdued } from 'design-system';
 import * as React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import { Issue } from '../../../types/types';
 import IssueTypeIcon from '../../icon-mappers/IssueTypeIcon';
@@ -36,7 +37,7 @@ export default function IssueType({ issue, ...iconProps }: Readonly<Props>) {
       content={<DeprecatedFieldTooltip field="type" />}
       links={[
         {
-          href: '/user-guide/issues',
+          href: DocLink.Issues,
           label: translate('learn_more'),
         },
       ]}
index 65eafc89f26158c61909be4a8d46dabf2e7a157b..f77f9224414c5c2a36143ef1739a489f06af5b1b 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { DismissableFlagMessage, Link } from 'design-system';
 import React, { useCallback, useEffect, useState } from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 import { Component } from '../../types/types';
 import { PreviouslyNonCompliantBranchNCD } from './utils';
@@ -33,9 +35,7 @@ interface NCDAutoUpdateMessageProps {
 export default function NCDAutoUpdateMessage(props: NCDAutoUpdateMessageProps) {
   const { component, previouslyNonCompliantBranchNCDs } = props;
   const intl = useIntl();
-  const toUrl = useDocUrl(
-    '/project-administration/clean-as-you-code-settings/defining-new-code/#new-code-definition-options',
-  );
+  const toUrl = useDocUrl(DocLink.NewCodeDefinitionOptions);
 
   const [dismissed, setDismissed] = useState(true);
 
index 95fe198617cd50701fb148b04eed8ca6eac5714c..855eccd37543f754a034802815736df1d4ffd458 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 import { translate } from '../../helpers/l10n';
 
 export default function NewCodeDefinitionAnalysisWarning() {
-  const toStatic = useDocUrl(
-    '/project-administration/clean-as-you-code-settings/defining-new-code/',
-  );
+  const toStatic = useDocUrl(DocLink.NewCodeDefinition);
   return (
     <FlagMessage variant="warning" className="sw-mb-4 sw-max-w-[800px]">
       <div>
index b47d9bb154eb85ecd00df2fc3362cfffe1831826..923953e56e95866ce471696267bce73678c6f36f 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   DismissableFlagMessage,
   FlagErrorIcon,
@@ -29,6 +30,7 @@ import * as React from 'react';
 import { useCallback, useEffect, useMemo, useState } from 'react';
 import { FormattedMessage } from 'react-intl';
 import { MessageTypes, checkMessageDismissed, setMessageDismissed } from '../../api/messages';
+import { DocLink } from '../../helpers/doc-links';
 import { translate, translateWithParameters } from '../../helpers/l10n';
 import {
   NUMBER_OF_DAYS_MAX_VALUE,
@@ -165,7 +167,7 @@ export default function NewCodeDefinitionDaysOption(props: Props) {
                     days: currentDaysValue,
                     date: isDefined(updatedAt) && new Date(updatedAt).toLocaleDateString(),
                     link: (
-                      <DocumentationLink to="/project-administration/clean-as-you-code-settings/defining-new-code/#new-code-definition-options">
+                      <DocumentationLink to={DocLink.NewCodeDefinitionOptions}>
                         {translate('learn_more')}
                       </DocumentationLink>
                     ),
index dbbd066e0e031ee71762fe01cc43cd2eaf02a93f..c1d0c4ea32e91b1ac9a21bc33a9d7ebb56874efe 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
+import { DocLink } from '../../helpers/doc-links';
 import DocumentationLink from '../common/DocumentationLink';
 
 interface AnalysisMissingInfoMessageProps {
@@ -47,10 +49,7 @@ export default function AnalysisMissingInfoMessage({
         values={{
           qualifier,
           learn_more: (
-            <DocumentationLink
-              className="sw-whitespace-nowrap"
-              to="/user-guide/clean-code/code-analysis/"
-            >
+            <DocumentationLink className="sw-whitespace-nowrap" to={DocLink.CodeAnalysis}>
               {intl.formatMessage({ id: 'learn_more' })}
             </DocumentationLink>
           ),
index 49d8f811c41c1018ccba1e281af07d66d03efe53..a22ec5113d32bc565f19c3b8d99fb09d93f6f847 100644 (file)
@@ -22,6 +22,7 @@ import { LinkHighlight, LinkStandalone } from '@sonarsource/echoes-react';
 import React, { useMemo } from 'react';
 import { FormattedMessage, useIntl } from 'react-intl';
 import { useAppState } from '../../app/components/app-state/withAppStateContext';
+import { DocLink } from '../../helpers/doc-links';
 import { useDocUrl } from '../../helpers/docs';
 import { getInstanceVersionNumber } from '../../helpers/strings';
 import { isCurrentVersionEOLActive } from '../../helpers/system';
@@ -39,7 +40,7 @@ export default function AppVersionStatus() {
     return isCurrentVersionEOLActive(versionEOL);
   }, [data?.installedVersionActive, versionEOL]);
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.ActiveVersions);
   const intl = useIntl();
 
   return intl.formatMessage(
@@ -47,11 +48,7 @@ export default function AppVersionStatus() {
     {
       version: getInstanceVersionNumber(version),
       status: (
-        <LinkStandalone
-          className="sw-ml-1"
-          highlight={LinkHighlight.CurrentColor}
-          to={docUrl('/setup-and-upgrade/upgrade-the-server/active-versions/')}
-        >
+        <LinkStandalone className="sw-ml-1" highlight={LinkHighlight.CurrentColor} to={docUrl}>
           <FormattedMessage
             id={`footer.version.status.${isActiveVersion ? 'active' : 'inactive'}`}
           />
index 2576467c00fe08baeaf7aed752005d82eb5810ca..ca2aed6d41642016070ee97a5783deb605a8f25f 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Pill } from 'design-system';
 import React from 'react';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { CleanCodeAttribute, CleanCodeAttributeCategory } from '../../types/clean-code-taxonomy';
 
@@ -57,7 +59,7 @@ export function CleanCodeAttributePill(props: Readonly<Props>) {
       }
       links={[
         {
-          href: '/user-guide/clean-code/introduction',
+          href: DocLink.CleanCodeIntroduction,
           label: translate('learn_more'),
         },
       ]}
index 4cc8a0ba848f9dfd394434ef058cc50546870813..c40f58220b2cd8d93e8aa8b9e8d3c5b77b5cd421 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import classNames from 'classnames';
 import { Pill } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
+import { DocLink } from '../../helpers/doc-links';
 import { translate } from '../../helpers/l10n';
 import { SoftwareImpactSeverity } from '../../types/clean-code-taxonomy';
 import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
@@ -56,7 +58,7 @@ export default function SoftwareImpactPill(props: Props) {
       }
       links={[
         {
-          href: '/user-guide/clean-code/introduction',
+          href: DocLink.CleanCodeIntroduction,
           label: translate('learn_more'),
         },
       ]}
index 518ed91fc82bce1fc7a867cd5f6276fcdbed4b88..194d057137aa89a7c0705b367880dd4cee3a3ffa 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { screen, waitFor } from '@testing-library/react';
 import userEvent from '@testing-library/user-event';
 import { UserEvent } from '@testing-library/user-event/dist/types/setup/setup';
@@ -74,7 +75,7 @@ const ui = {
     'onboarding.tutorial.with.github_action.create_secret.monorepo_project_level_token_info.link',
   ),
   monoRepoYamlDocLink: byRole('link', {
-    name: 'onboarding.tutorial.with.github_action.monorepo.see_yaml_instructions',
+    name: /^onboarding\.tutorial\.with\.github_action\.monorepo\.see_yaml_instructions\b/,
   }),
   chooseTutorialLink: (mode: TutorialModes) =>
     byRole('link', { name: `onboarding.tutorial.choose_method.${mode}` }),
index 516cb52de8ab6a8cbd9d3409d08779184b200535..2124f129f3f338af851f71bec0a2d5cad72ce685 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys } from '../../../../types/alm-settings';
 
 export default function AlertClassicEditor() {
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.AlmAzureIntegration);
 
   return (
     <FlagMessage variant="info" className="sw-mt-4">
@@ -36,7 +36,7 @@ export default function AlertClassicEditor() {
           defaultMessage={translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info')}
           values={{
             doc_link: (
-              <Link to={docUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure])}>
+              <Link to={docUrl}>
                 {translate('onboarding.tutorial.with.azure_pipelines.BranchAnalysis.info.doc_link')}
               </Link>
             ),
index ceb1e9286f1adb86521bed3b2738bd81f8e41f4c..74a9c5fcaee221b6b94989869d3f8d2673729bf5 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { BasicSeparator, FlagMessage, Link, NumberedListItem } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import withAvailableFeatures, {
   WithAvailableFeaturesProps,
 } from '../../../../app/components/available-features/withAvailableFeatures';
-import { ALM_DOCUMENTATION_PATHS } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
-import { AlmKeys } from '../../../../types/alm-settings';
 import { Feature } from '../../../../types/features';
 import SentenceWithHighlights from '../../components/SentenceWithHighlights';
 
@@ -35,7 +35,7 @@ export interface PublishStepsProps extends WithAvailableFeaturesProps {}
 export function PublishSteps(props: PublishStepsProps) {
   const branchSupportEnabled = props.hasFeature(Feature.BranchSupport);
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.AlmAzureIntegration);
 
   return (
     <>
@@ -71,7 +71,7 @@ export function PublishSteps(props: PublishStepsProps) {
               )}
               values={{
                 link: (
-                  <Link to={docUrl(ALM_DOCUMENTATION_PATHS[AlmKeys.Azure])}>
+                  <Link to={docUrl}>
                     {translate(
                       'onboarding.tutorial.with.azure_pipelines.BranchAnalysis.branch_protection.link',
                     )}
index ad40eaf80b37ae2b27d4c870deb2631303b0816e..3b5e5aeea418584f94096e7e711bf05497cf1ab4 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
@@ -39,7 +41,7 @@ export function CompilationInfo({ className = 'sw-my-2' }: CompilationInfoProps)
             defaultMessage={translate('onboarding.tutorial.cfamilly.compilation_database_info')}
             values={{
               link: (
-                <Link to={docUrl('/analyzing-source-code/languages/c-family/')}>
+                <Link to={docUrl(DocLink.CFamily)}>
                   {translate('onboarding.tutorial.cfamilly.compilation_database_info.link')}
                 </Link>
               ),
@@ -52,7 +54,7 @@ export function CompilationInfo({ className = 'sw-my-2' }: CompilationInfoProps)
             defaultMessage={translate('onboarding.tutorial.cfamilly.speed_caching')}
             values={{
               link: (
-                <Link to={docUrl('/analyzing-source-code/languages/c-family/#analysis-cache')}>
+                <Link to={docUrl(DocLink.CFamilyAnalysisCache)}>
                   {translate('onboarding.tutorial.cfamilly.speed_caching.link')}
                 </Link>
               ),
index dd1718918cda13a8c870413bec11ded6328a0e30..8d3ba1de36c5d59be73c22bfde166b64ab3cf3f2 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import classNames from 'classnames';
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 
@@ -29,7 +31,7 @@ export interface ProjectTokenScopeInfoProps {
 }
 
 export default function ProjectTokenScopeInfo({ className }: ProjectTokenScopeInfoProps) {
-  const docUrl = useDocUrl('/user-guide/user-account/generating-and-using-tokens/');
+  const docUrl = useDocUrl(DocLink.AccountTokens);
 
   return (
     <FlagMessage variant="info" className={classNames('sw-mt-2', className)}>
index 0ae8b529271172ad120a5c79c2ef55e0b8ce00eb..5a6cd34cf3c6a73238898b3d05fca153cdf6bb33 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { NumberedListItem } from 'design-system';
 import * as React from 'react';
+import { DocLink } from '../../../../helpers/doc-links';
 import { translate } from '../../../../helpers/l10n';
 import DocumentationLink from '../../../common/DocumentationLink';
 
-const MONOREPO_DOC =
-  '/devops-platform-integration/github-integration/monorepo/#workflow-file-example';
-
 export default function MonorepoDocLinkFallback() {
   return (
     <NumberedListItem>
-      <DocumentationLink className="sw-mt-4" to={MONOREPO_DOC}>
+      <DocumentationLink className="sw-mt-4" to={DocLink.AlmGitHubMonorepoWorkfileExample}>
         {translate('onboarding.tutorial.with.github_action.monorepo.see_yaml_instructions')}
       </DocumentationLink>
     </NumberedListItem>
index 97d1ec558cbcb88bcdbea44268d4302fe8a845d8..da01cd504e50aaf557c677ec5bd9e03a22457e9a 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { FlagMessage, Link, ListItem, TutorialStep, UnorderedList } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 import { AlmKeys } from '../../../types/alm-settings';
@@ -33,7 +35,7 @@ export interface PreRequisitesStepProps {
 export default function PreRequisitesStep(props: PreRequisitesStepProps) {
   const { alm, branchesEnabled } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.CIJenkins);
 
   return (
     <TutorialStep title={translate('onboarding.tutorial.with.jenkins.prereqs.title')}>
@@ -66,7 +68,7 @@ export default function PreRequisitesStep(props: PreRequisitesStepProps) {
           id="onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide"
           values={{
             link: (
-              <Link to={docUrl('/analyzing-source-code/ci-integration/jenkins-integration/')}>
+              <Link to={docUrl}>
                 {translate('onboarding.tutorial.with.jenkins.prereqs.step_by_step_guide.link')}
               </Link>
             ),
index e5f536ac0ac0ba5d1a5defd68ed0d9167841ff76..f97fca6d662d5c7be09200422b0ec59c306a65b7 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import styled from '@emotion/styled';
 import { animated, config, useSpring } from '@react-spring/web';
 import { BasicSeparator, FlagVisual, Link } from 'design-system';
 import * as React from 'react';
+import { DocLink } from '../../../helpers/doc-links';
 import { useDocUrl } from '../../../helpers/docs';
 import { translate } from '../../../helpers/l10n';
 import useIntersectionObserver from '../../../hooks/useIntersectionObserver';
@@ -75,7 +77,7 @@ export default function DoneNextSteps({ component }: DoneNextStepsProps) {
           </span>
           <ul className="sw-flex sw-flex-col sw-gap-2 sw-mt-2">
             <li>
-              <Link to={docUrl('/analyzing-source-code/branches/branch-analysis/')}>
+              <Link to={docUrl(DocLink.BranchAnalysis)}>
                 {translate(
                   'onboarding.analysis.auto_refresh_after_analysis.check_these_links.branches',
                 )}
@@ -83,7 +85,7 @@ export default function DoneNextSteps({ component }: DoneNextStepsProps) {
             </li>
 
             <li>
-              <Link to={docUrl('/analyzing-source-code/pull-request-analysis')}>
+              <Link to={docUrl(DocLink.PullRequestAnalysis)}>
                 {translate(
                   'onboarding.analysis.auto_refresh_after_analysis.check_these_links.pr_analysis',
                 )}
index 452c30a01e994a900822b29f075c3615f0177405..417e999a5f1b8ef1af83653c8f2b03f31c882a1c 100644 (file)
@@ -43,6 +43,7 @@ import { FormattedMessage } from 'react-intl';
 import { SingleValue } from 'react-select';
 import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
 import { generateToken, getTokens, revokeToken } from '../../../api/user-tokens';
+import { DocLink } from '../../../helpers/doc-links';
 import { translate } from '../../../helpers/l10n';
 import {
   EXPIRATION_OPTIONS,
@@ -218,7 +219,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
                 content={translate('onboarding.token.name.help')}
                 links={[
                   {
-                    href: '/user-guide/user-account/generating-and-using-tokens/',
+                    href: DocLink.AccountTokens,
                     label: translate('learn_more'),
                   },
                 ]}
@@ -281,7 +282,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
                 content={translate('onboarding.token.use_existing_token.help')}
                 links={[
                   {
-                    href: '/user-guide/user-account/generating-and-using-tokens/',
+                    href: DocLink.AccountTokens,
                     label: translate('learn_more'),
                   },
                 ]}
index 4266c35def5d70642c5438cade09e0a56aa0ea06..ca6335d88d2555a9da4772ce260376c0249468fa 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { CodeSnippet, Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
@@ -32,7 +34,7 @@ export interface DotNetExecuteProps {
 }
 
 export default function DotNetExecute({ commands, component }: DotNetExecuteProps) {
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScannerDotNet);
 
   return (
     <>
@@ -58,11 +60,7 @@ export default function DotNetExecute({ commands, component }: DotNetExecuteProp
           defaultMessage={translate('onboarding.analysis.docs')}
           id="onboarding.analysis.docs"
           values={{
-            link: (
-              <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-dotnet/')}>
-                {translate('onboarding.analysis.msbuild.docs_link')}
-              </Link>
-            ),
+            link: <Link to={docUrl}>{translate('onboarding.analysis.msbuild.docs_link')}</Link>,
           }}
         />
       </p>
index 7c0020a4ecc405530c2cdf2ea4c88d91f73bf124..fd9ef57f29bd6cdf546501135027da37aa5d4abf 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { InlineSnippet } from '../../components/InlineSnippet';
@@ -29,7 +31,7 @@ import DotNetExecute from './DotNetExecute';
 export default function DotNetFramework(props: DotNetProps) {
   const { baseUrl, component, token } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScannerDotNet);
 
   const commands = [
     `SonarScanner.MSBuild.exe begin /k:"${component.key}" /d:sonar.host.url="${baseUrl}" /d:sonar.token="${token}"`,
@@ -49,11 +51,7 @@ export default function DotNetFramework(props: DotNetProps) {
             id="onboarding.analysis.msbuild.text"
             values={{
               code: <InlineSnippet snippet="%PATH%" />,
-              link: (
-                <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-dotnet/')}>
-                  {translate('onboarding.analysis.msbuild.docs_link')}
-                </Link>
-              ),
+              link: <Link to={docUrl}>{translate('onboarding.analysis.msbuild.docs_link')}</Link>,
             }}
           />
         </p>
index 29f2772cd485556b6151fee741a699212417e47e..b914eaa49600d180f389588280029952f6dbd5b0 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import {
   ClipboardIconButton,
   CodeSnippet,
@@ -27,6 +28,7 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { InlineSnippet } from '../../components/InlineSnippet';
@@ -41,7 +43,7 @@ export interface DownloadScannerProps {
 export default function DownloadScanner(props: DownloadScannerProps) {
   const { os, isLocal, token } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScanner);
 
   return (
     <div className="sw-mb-4">
@@ -57,9 +59,7 @@ export default function DownloadScanner(props: DownloadScannerProps) {
               dir: <InlineSnippet snippet="bin" />,
               env_var: <InlineSnippet snippet={os === OSs.Windows ? '%PATH%' : 'PATH'} />,
               link: (
-                <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner/')}>
-                  {translate('onboarding.analysis.sq_scanner.docs_link')}
-                </Link>
+                <Link to={docUrl}>{translate('onboarding.analysis.sq_scanner.docs_link')}</Link>
               ),
             }}
           />
index 52913bcf66e6156867affd72859c8b77c132fdbd..1ac8372adf01a47b26b8ab26a4a177d2575f8d3d 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { CodeSnippet, Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { OSs } from '../../types';
@@ -37,7 +39,7 @@ const executables: { [x in OSs]: string } = {
 export default function ExecBuildWrapper(props: ExecBuildWrapperProps) {
   const { os } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.CFamily);
 
   return (
     <>
@@ -58,9 +60,7 @@ export default function ExecBuildWrapper(props: ExecBuildWrapperProps) {
           id="onboarding.analysis.build_wrapper.docs"
           values={{
             link: (
-              <Link to={docUrl('/analyzing-source-code/languages/c-family/')}>
-                {translate('onboarding.analysis.build_wrapper.docs_link')}
-              </Link>
+              <Link to={docUrl}>{translate('onboarding.analysis.build_wrapper.docs_link')}</Link>
             ),
           }}
         />
index 2a99c8fb01dc9dbb472e5a4961f12d8002272c4b..c208abb4b73e1bb4e3338fd1a59fda1b3df84359 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { CodeSnippet, Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
@@ -40,7 +42,7 @@ export interface ExecScannerProps {
 export default function ExecScanner(props: ExecScannerProps) {
   const { baseUrl, os, isLocal, component, token, cfamily } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScanner);
 
   const q = quote(os);
   const command = [
@@ -66,11 +68,7 @@ export default function ExecScanner(props: ExecScannerProps) {
           defaultMessage={translate('onboarding.analysis.sq_scanner.docs')}
           id="onboarding.analysis.sq_scanner.docs"
           values={{
-            link: (
-              <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner/')}>
-                {translate('onboarding.analysis.sq_scanner.docs_link')}
-              </Link>
-            ),
+            link: <Link to={docUrl}>{translate('onboarding.analysis.sq_scanner.docs_link')}</Link>,
           }}
         />
       </p>
index d707c099e4808715e1e22b9aa5e89f89975d8f58..858302848b487ff2c567c23ed46fec266d9aab89 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { CodeSnippet, Link, Note, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { GRADLE_SCANNER_VERSION } from '../../../../helpers/constants';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
@@ -54,7 +56,7 @@ const config = {
 export default function JavaGradle(props: JavaGradleProps) {
   const { baseUrl, component, token } = props;
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScannerGradle);
 
   const command = [
     './gradlew sonar',
@@ -99,11 +101,7 @@ export default function JavaGradle(props: JavaGradleProps) {
             defaultMessage={translate('onboarding.analysis.java.gradle.latest_version')}
             id="onboarding.analysis.java.gradle.latest_version"
             values={{
-              link: (
-                <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-gradle/')}>
-                  {translate('here')}
-                </Link>
-              ),
+              link: <Link to={docUrl}>{translate('here')}</Link>,
             }}
           />
         </Note>
@@ -115,11 +113,7 @@ export default function JavaGradle(props: JavaGradleProps) {
           defaultMessage={translate('onboarding.analysis.docs')}
           id="onboarding.analysis.docs"
           values={{
-            link: (
-              <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-gradle/')}>
-                {translate('onboarding.analysis.java.gradle.docs_link')}
-              </Link>
-            ),
+            link: <Link to={docUrl}>{translate('onboarding.analysis.java.gradle.docs_link')}</Link>,
           }}
         />
       </p>
index b1452e271bb71e00574f707bce565a2eddb9bf7f..9fb6c7169437d2fc80f8a5a2dc3c13b9dab16f58 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { CodeSnippet, Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../../../helpers/doc-links';
 import { useDocUrl } from '../../../../helpers/docs';
 import { translate } from '../../../../helpers/l10n';
 import { Component } from '../../../../types/types';
@@ -42,7 +44,7 @@ export default function JavaMaven(props: JavaMavenProps) {
     `-Dsonar.token=${token}`,
   ];
 
-  const docUrl = useDocUrl();
+  const docUrl = useDocUrl(DocLink.SonarScannerMaven);
 
   return (
     <div>
@@ -58,11 +60,7 @@ export default function JavaMaven(props: JavaMavenProps) {
           defaultMessage={translate('onboarding.analysis.docs')}
           id="onboarding.analysis.docs"
           values={{
-            link: (
-              <Link to={docUrl('/analyzing-source-code/scanners/sonarscanner-for-maven/')}>
-                {translate('onboarding.analysis.java.maven.docs_link')}
-              </Link>
-            ),
+            link: <Link to={docUrl}>{translate('onboarding.analysis.java.maven.docs_link')}</Link>,
           }}
         />
       </p>
index 9a3e5e5118b9339976d213876bf063904561352f..8ad9a91bb502e910db205f81cc5cfd1ca3c801f0 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { DownloadButton, Link, SubHeading } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
+import { DocLink } from '../../helpers/doc-links';
 import {
   getEdition,
   getEditionDownloadFilename,
@@ -94,7 +96,7 @@ export default function SystemUpgradeItem(props: SystemUpgradeItemProps) {
           {translateWithParameters('system.download_x', lastUpgrade.version)}
         </DownloadButton>
 
-        <DocumentationLink className="sw-ml-2" to="/setup-and-upgrade/upgrade-the-server/roadmap/">
+        <DocumentationLink className="sw-ml-2" to={DocLink.ServerUpgradeRoadmap}>
           {translate('system.how_to_upgrade')}
         </DocumentationLink>
       </div>
index 1d236dad89cbd8cb631dcf1fb6f73337ee245159..1878e24ba20cbf404c32ab59440918e93a5f8624 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ComponentQualifier } from '~sonar-aligned/types/component';
 import { MetricKey } from '~sonar-aligned/types/metrics';
 import { colors } from '../app/theme';
@@ -167,16 +168,6 @@ export const DEPRECATED_ACTIVITY_METRICS = [
 
 export const PROJECT_KEY_MAX_LEN = 400;
 
-export const ALM_DOCUMENTATION_PATHS = {
-  [AlmKeys.Azure]: '/devops-platform-integration/azure-devops-integration/',
-  [AlmKeys.BitbucketServer]:
-    '/devops-platform-integration/bitbucket-integration/bitbucket-server-integration/',
-  [AlmKeys.BitbucketCloud]:
-    '/devops-platform-integration/bitbucket-integration/bitbucket-cloud-integration/',
-  [AlmKeys.GitHub]: '/devops-platform-integration/github-integration/',
-  [AlmKeys.GitLab]: '/devops-platform-integration/gitlab-integration/',
-};
-
 export const IMPORT_COMPATIBLE_ALMS = [
   AlmKeys.Azure,
   AlmKeys.BitbucketServer,
diff --git a/server/sonar-web/src/main/js/helpers/doc-links.ts b/server/sonar-web/src/main/js/helpers/doc-links.ts
new file mode 100644 (file)
index 0000000..271234d
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2024 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
+ */
+
+import { AlmKeys } from '../types/alm-settings';
+
+export const DOC_URL = 'https://docs.sonarsource.com/sonarqube/latest';
+
+export enum DocLink {
+  AccountTokens = '/user-guide/user-account/generating-and-using-tokens/',
+  ActiveVersions = '/setup-and-upgrade/upgrade-the-server/active-versions/',
+  AlmAzureIntegration = '/devops-platform-integration/azure-devops-integration/',
+  AlmBitBucketCloudAuth = '/instance-administration/authentication/bitbucket-cloud/',
+  AlmBitBucketCloudIntegration = '/devops-platform-integration/bitbucket-integration/bitbucket-cloud-integration/',
+  AlmBitBucketCloudSettings = '/instance-administration/authentication/bitbucket-cloud/#setting-your-authentication-settings-in-sonarqube',
+  AlmBitBucketServerIntegration = '/devops-platform-integration/bitbucket-integration/bitbucket-server-integration/',
+  AlmGitHubAuth = '/instance-administration/authentication/github/',
+  AlmGitHubIntegration = '/devops-platform-integration/github-integration/',
+  AlmGitHubMonorepoWorkfileExample = '/devops-platform-integration/github-integration/monorepo/#workflow-file-example',
+  AlmGitLabAuth = '/instance-administration/authentication/gitlab/',
+  AlmGitLabAuthProvisioningMethod = '/instance-administration/authentication/gitlab/#choosing-the-provisioning-method',
+  AlmGitLabIntegration = '/devops-platform-integration/gitlab-integration/',
+  AlmSamlAuth = '/instance-administration/authentication/saml/overview/',
+  AlmSamlScimAuth = '/instance-administration/authentication/saml/scim/overview/',
+  AnalysisScope = '/project-administration/analysis-scope/',
+  AuthOverview = '/instance-administration/authentication/overview/',
+  BackgroundTasks = '/analyzing-source-code/background-tasks/',
+  BranchAnalysis = '/analyzing-source-code/branches/branch-analysis/',
+  CaYC = '/user-guide/clean-as-you-code/',
+  CFamily = '/analyzing-source-code/languages/c-family/',
+  CFamilyAnalysisCache = '/analyzing-source-code/languages/c-family/#analysis-cache',
+  CIAnalysisSetup = '/analyzing-source-code/ci-integration/overview/',
+  CIJenkins = '/analyzing-source-code/ci-integration/jenkins-integration/',
+  CleanCodeIntroduction = '/user-guide/clean-code/introduction/',
+  CodeAnalysis = '/user-guide/clean-code/code-analysis/',
+  InactiveBranches = '/analyzing-source-code/branches/branch-analysis/#inactive-branches',
+  InstanceAdminEncryption = '/instance-administration/security/#settings-encryption',
+  InstanceAdminLicense = '/instance-administration/license-administration/',
+  InstanceAdminLoC = '/instance-administration/monitoring/lines-of-code/',
+  InstanceAdminMarketplace = '/instance-administration/marketplace/',
+  InstanceAdminPluginVersionMatrix = '/instance-administration/plugin-version-matrix/',
+  InstanceAdminQualityProfiles = '/instance-administration/quality-profiles/',
+  InstanceAdminReindexation = '/instance-administration/reindexing/',
+  InstanceAdminSecurity = '/instance-administration/security/',
+  IssueResolutions = '/user-guide/issues/#resolutions-deprecated',
+  Issues = '/user-guide/issues',
+  IssueStatuses = '/user-guide/issues/#statuses',
+  MainBranchAnalysis = '/analyzing-source-code/branches/branch-analysis/#main-branch',
+  MetricDefinitions = '/user-guide/metric-definitions/',
+  Monorepos = '/project-administration/monorepos/',
+  NewCodeDefinition = '/project-administration/clean-as-you-code-settings/defining-new-code/',
+  NewCodeDefinitionOptions = '/project-administration/clean-as-you-code-settings/defining-new-code/#new-code-definition-options',
+  Portfolios = '/user-guide/portfolios/',
+  PullRequestAnalysis = '/analyzing-source-code/pull-request-analysis',
+  QualityGates = '/user-guide/quality-gates/',
+  Root = '/',
+  RulesOverview = '/user-guide/rules/overview',
+  SecurityHotspots = '/user-guide/security-hotspots/',
+  SecurityReports = '/user-guide/security-reports/',
+  ServerUpgradeRoadmap = '/setup-and-upgrade/upgrade-the-server/roadmap/',
+  SonarLintConnectedMode = '/user-guide/sonarlint-connected-mode/',
+  SonarScanner = '/analyzing-source-code/scanners/sonarscanner/',
+  SonarScannerDotNet = '/analyzing-source-code/scanners/sonarscanner-for-dotnet/',
+  SonarScannerGradle = '/analyzing-source-code/scanners/sonarscanner-for-gradle/',
+  SonarScannerMaven = '/analyzing-source-code/scanners/sonarscanner-for-maven/',
+  Webhooks = '/project-administration/webhooks/',
+}
+
+export const DocTitle = {
+  [DocLink.BackgroundTasks]: 'About Background Tasks',
+  [DocLink.CaYC]: 'Clean as You Code',
+  [DocLink.CIAnalysisSetup]: 'Set up CI analysis',
+  [DocLink.InstanceAdminQualityProfiles]: 'About Quality Profiles',
+  [DocLink.MetricDefinitions]: 'Metric Definitions',
+  [DocLink.NewCodeDefinition]: 'Defining New Code',
+  [DocLink.PullRequestAnalysis]: 'Analyzing Pull Requests',
+  [DocLink.SecurityReports]: 'About Security Reports',
+  [DocLink.SonarLintConnectedMode]: 'SonarLint Connected Mode',
+  [DocLink.Webhooks]: 'About Webhooks',
+};
+
+export type DocTitleKey = keyof typeof DocTitle;
+
+const asDocSections = <T>(element: { [K in keyof T]: DocTitleKey[] }) => element;
+
+export const DocSection = asDocSections({
+  component_measures: [DocLink.CaYC, DocLink.MetricDefinitions],
+  overview: [
+    DocLink.PullRequestAnalysis,
+    DocLink.CIAnalysisSetup,
+    DocLink.CaYC,
+    DocLink.SonarLintConnectedMode,
+  ],
+  pull_requests: [DocLink.CaYC, DocLink.PullRequestAnalysis, DocLink.SonarLintConnectedMode],
+});
+
+export type DocSectionKey = keyof typeof DocSection;
+
+export const AlmAuthDocLinkKeys = {
+  [AlmKeys.BitbucketServer]: DocLink.AlmBitBucketCloudAuth,
+  [AlmKeys.GitHub]: DocLink.AlmGitHubAuth,
+  [AlmKeys.GitLab]: DocLink.AlmGitLabAuth,
+  saml: DocLink.AlmSamlAuth,
+};
index 31f34ecbb303354e38d1cba2a2baa2bc5ebe5abe..ac32f8e5005f8ef4459d4f69627078343f93f15b 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import React from 'react';
 import { AppStateContext } from '../app/components/app-state/AppStateContext';
+import { DocLink } from './doc-links';
 
-export function getUrlForDoc(url: string, version: string, to: string) {
-  const isSnapshot = version.indexOf('SNAPSHOT') !== -1;
-  const path = to.replace(/^\//, '');
+// This is only meant to be used directly for DocumentationRedirect. For all other uses,
+// please use useDocUrl instead (it forces the use of a catalogued documentation link)
+export function useUncataloguedDocUrl(to?: string) {
+  const { version, documentationUrl: docUrl } = React.useContext(AppStateContext);
 
-  return isSnapshot
-    ? `${url.replace(url.slice(url.lastIndexOf('/')), '/latest')}/${path}`
-    : `${url}/${path}`;
-}
+  const formatDocUrl = React.useCallback(
+    (href: string) => {
+      const isSnapshot = version.indexOf('SNAPSHOT') !== -1;
 
-export function useDocUrl(to: string): string;
-export function useDocUrl(): (to: string) => string;
-export function useDocUrl(to?: string) {
-  const { version, documentationUrl } = React.useContext(AppStateContext);
+      const path = href.replace(/^\//, '');
 
-  if (to) {
-    return getUrlForDoc(documentationUrl, version, to);
-  }
+      return isSnapshot
+        ? `${docUrl.replace(docUrl.slice(docUrl.lastIndexOf('/')), '/latest')}/${path}`
+        : `${docUrl}/${path}`;
+    },
+    [docUrl, version],
+  );
+
+  return to ? formatDocUrl(to) : formatDocUrl;
+}
 
-  return (to: string) => getUrlForDoc(documentationUrl, version, to);
+export function useDocUrl(to: DocLink): string;
+export function useDocUrl(): (to: DocLink) => string;
+export function useDocUrl(to?: DocLink) {
+  return useUncataloguedDocUrl(to);
 }
index 19d0e4f0ab20a68c619ae841c76d5c3a5be4f8e6..70b391f9ef64ca95f4aea47d17568f0d2fae899a 100644 (file)
@@ -17,6 +17,7 @@
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import classNames from 'classnames';
 import { HelperHintIcon } from 'design-system';
 import { first, last } from 'lodash';
@@ -24,6 +25,7 @@ import * as React from 'react';
 import DocumentationLink from '../../../components/common/DocumentationLink';
 import Link from '../../../components/common/Link';
 import Tooltip, { Placement } from '../../../components/controls/Tooltip';
+import { DocLink } from '../../../helpers/doc-links';
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate } from '../../../helpers/l10n';
 
@@ -32,7 +34,12 @@ export interface DocHelpTooltipProps {
   className?: string;
   content?: React.ReactNode;
   linkTextLabel?: string;
-  links?: Array<{ href: string; label?: string; inPlace?: boolean; doc?: boolean }>;
+  links?: Array<
+    { label?: string; inPlace?: boolean } & (
+      | { doc?: true; href: DocLink }
+      | { doc: false; href: string }
+    )
+  >;
   placement?: Placement;
   title?: string;
 }
@@ -91,7 +98,10 @@ export default function DocHelpTooltip(props: Readonly<DocHelpTooltipProps>) {
             <div className="sw-mb-1" key={label}>
               {index === 0 && linkTextLabel && `${linkTextLabel}: `}
               {doc ? (
-                <DocumentationLink to={href} innerRef={(ref) => (linksRef.current[index] = ref)}>
+                <DocumentationLink
+                  to={href as DocLink} // the map above messed up type inference
+                  innerRef={(ref) => (linksRef.current[index] = ref)}
+                >
                   {label}
                 </DocumentationLink>
               ) : (
index 1f58f3d7db829d326b461db5bc7d657f774634d1..e9cc67e6798be87ab7fbf66d7c1d743c30d39a95 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import userEvent from '@testing-library/user-event';
 import * as React from 'react';
 import { byRole, byTestId } from '../../../helpers/testSelector';
 
 import Link from '../../../../components/common/Link';
+import { DocLink } from '../../../../helpers/doc-links';
 import { renderComponent } from '../../../../helpers/testReactTestingUtils';
 import DocHelpTooltip, { DocHelpTooltipProps } from '../DocHelpTooltip';
 
@@ -31,7 +33,7 @@ const ui = {
   helpIcon: byTestId('help-tooltip-activator'),
   helpLink: byRole('link', { name: 'Icon' }),
   linkInTooltip: byRole('link', { name: 'Label' }),
-  linkInTooltip2: byRole('link', { name: 'Label2' }),
+  linkInTooltip2: byRole('link', { name: /^Label2\b/ }),
   afterLink: byRole('link', { name: 'Interactive element after' }),
 };
 
@@ -70,15 +72,15 @@ function renderDocHelpTooltip(props: Partial<DocHelpTooltipProps> = {}) {
         content="Tooltip content"
         links={[
           {
-            href: '/user-guide/clean-as-you-code/',
-            label: 'Label',
             doc: false,
+            href: '/user-guide/clean-as-you-code2/',
+            label: 'Label',
           },
           {
-            href: '/user-guide/clean-as-you-code2/',
-            label: 'Label2',
             doc: true,
+            href: DocLink.CaYC,
             inPlace: true,
+            label: 'Label2',
           },
         ]}
         {...props}
index 4737531b46270a090b28764b33cb071457d8bc20..ae90f771e9a78b409063a262e32e4a2dcca0a98f 100644 (file)
  * along with this program; if not, write to the Free Software Foundation,
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
+
 import { ComponentBase, ComponentQualifier } from '~sonar-aligned/types/component';
 import { RuleDescriptionSection } from '../apps/coding-rules/rule';
+import { DocTitleKey } from '../helpers/doc-links';
 import {
   CleanCodeAttribute,
   CleanCodeAttributeCategory,
@@ -685,8 +687,7 @@ export interface SubscriptionPlan {
 }
 
 export interface SuggestionLink {
-  link: string;
-  scope?: 'sonarcloud';
+  link: DocTitleKey;
   text: string;
 }