]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-22049 Align HelpTooltip And DocHelpTooltip (DocumentationTooltip)
authorViktor Vorona <viktor.vorona@sonarsource.com>
Mon, 22 Apr 2024 12:35:10 +0000 (14:35 +0200)
committerMatteo Mara <matteo.mara@sonarsource.com>
Tue, 30 Apr 2024 08:59:03 +0000 (10:59 +0200)
61 files changed:
server/sonar-web/src/main/js/app/components/nav/component/branch-like/BranchHelpTooltip.tsx
server/sonar-web/src/main/js/app/components/nav/component/branch-like/MenuItemList.tsx
server/sonar-web/src/main/js/apps/account/profile/Profile.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/StatPendingTime.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/StatStillFailing.tsx
server/sonar-web/src/main/js/apps/background-tasks/components/Workers.tsx
server/sonar-web/src/main/js/apps/code/components/CodeAppRenderer.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/ProfileFacet.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetails.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsHeaderActions.tsx
server/sonar-web/src/main/js/apps/coding-rules/components/RuleDetailsHeaderMeta.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/coding-rules/components/TemplateFacet.tsx
server/sonar-web/src/main/js/apps/component-measures/components/ComponentMeasuresApp.tsx
server/sonar-web/src/main/js/apps/component-measures/drilldown/BubbleChartView.tsx
server/sonar-web/src/main/js/apps/component-measures/sidebar/DomainSubnavigation.tsx
server/sonar-web/src/main/js/apps/create/project/CreateProjectModeSelection.tsx
server/sonar-web/src/main/js/apps/issues/sidebar/SeverityFacet.tsx
server/sonar-web/src/main/js/apps/overview/branches/ApplicationLeakPeriodInfo.tsx
server/sonar-web/src/main/js/apps/overview/branches/QualityGateStatusTitle.tsx
server/sonar-web/src/main/js/apps/overview/components/IgnoredConditionWarning.tsx
server/sonar-web/src/main/js/apps/overview/pullRequests/BranchQualityGate.tsx
server/sonar-web/src/main/js/apps/permission-templates/components/ListHeader.tsx
server/sonar-web/src/main/js/apps/permission-templates/components/PermissionCell.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/BranchLikeTable.tsx
server/sonar-web/src/main/js/apps/projectBranches/components/BranchPurgeSetting.tsx
server/sonar-web/src/main/js/apps/projectInformation/about/components/MetaKey.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/filters/QualityGateFilter.tsx
server/sonar-web/src/main/js/apps/projectsManagement/Search.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/CaycCondition.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/DetailsContent.tsx
server/sonar-web/src/main/js/apps/quality-gates/components/ListHeader.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRules.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesDeprecatedWarning.tsx
server/sonar-web/src/main/js/apps/quality-profiles/details/ProfileRulesSonarWayComparison.tsx
server/sonar-web/src/main/js/apps/quality-profiles/home/ProfilesList.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotSidebarHeader.tsx
server/sonar-web/src/main/js/apps/sessions/components/OAuthProviders.tsx
server/sonar-web/src/main/js/apps/settings/components/almIntegration/AlmBindingDefinitionBox.tsx
server/sonar-web/src/main/js/apps/users/UsersApp.tsx
server/sonar-web/src/main/js/apps/users/UsersList.tsx
server/sonar-web/src/main/js/apps/web-api-v2/components/ApiSidebar.tsx
server/sonar-web/src/main/js/apps/web-api/components/Search.tsx
server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx [deleted file]
server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx [deleted file]
server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx [deleted file]
server/sonar-web/src/main/js/components/controls/Tooltip.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/permissions/PermissionHeader.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/jenkins/buildtool-steps/CreateJenkinsfileBulletPoint.tsx
server/sonar-web/src/main/js/components/tutorials/other/TokenStep.tsx
server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx [new file with mode: 0644]
server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx [new file with mode: 0644]

index bc23a0d9ae082b3568b059a71657ec30b37bdef2..53585914f9ce42aa862022730df8832c60e34f3e 100644 (file)
 import { Link } from '@sonarsource/echoes-react';
 import { HelperHintIcon } from 'design-system';
 import React from 'react';
-import DocumentationTooltip from '../../../../../components/common/DocumentationTooltip';
-import HelpTooltip from '../../../../../components/controls/HelpTooltip';
 import { translate, translateWithParameters } from '../../../../../helpers/l10n';
 import { getApplicationAdminUrl } from '../../../../../helpers/urls';
 import { useProjectBindingQuery } from '../../../../../queries/devops-integration';
+import DocHelpTooltip from '../../../../../sonar-aligned/components/controls/DocHelpTooltip';
+import HelpTooltip from '../../../../../sonar-aligned/components/controls/HelpTooltip';
 import { AlmKeys } from '../../../../../types/alm-settings';
 import { Component } from '../../../../../types/types';
 
@@ -68,7 +68,7 @@ export default function BranchHelpTooltip({
   } else {
     if (!branchSupportEnabled) {
       return (
-        <DocumentationTooltip
+        <DocHelpTooltip
           content={
             projectBinding != null
               ? translateWithParameters(
@@ -92,13 +92,13 @@ export default function BranchHelpTooltip({
           }
         >
           {helpIcon}
-        </DocumentationTooltip>
+        </DocHelpTooltip>
       );
     }
 
     if (!hasManyBranches) {
       return (
-        <DocumentationTooltip
+        <DocHelpTooltip
           content={translate('branch_like_navigation.only_one_branch.content')}
           data-test="only-one-branch-like"
           links={[
@@ -120,7 +120,7 @@ export default function BranchHelpTooltip({
           title={translate('branch_like_navigation.only_one_branch.title')}
         >
           {helpIcon}
-        </DocumentationTooltip>
+        </DocHelpTooltip>
       );
     }
   }
index db0622414812bf299c41cd755261f927bcd2eb95..de5014e202c4b5a26842939d52ad84b76d996983 100644 (file)
  */
 import { HelperHintIcon, ItemDivider, ItemHeader } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../../../components/controls/HelpTooltip';
 import { getBranchLikeKey, isSameBranchLike } from '../../../../../helpers/branch-like';
 import { translate } from '../../../../../helpers/l10n';
 import { isDefined } from '../../../../../helpers/types';
+import HelpTooltip from '../../../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike, BranchLikeTree } from '../../../../../types/branch-like';
 import MenuItem from './MenuItem';
 
index 05e4a1a7f7ea5ccc6dc0bb7da018319a1efd5772..340bb851e22f90d558f7767ca81c9df6c8fb69cd 100644 (file)
@@ -20,9 +20,9 @@
 import { GreySeparator, HelperHintIcon, SubHeading, Title } from 'design-system';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { whenLoggedIn } from '../../../components/hoc/whenLoggedIn';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { LoggedInUser } from '../../../types/users';
 import { Preferences } from './Preferences';
 import UserExternalIdentity from './UserExternalIdentity';
index 51866966d15263a13364fd6d6fe9594f3e14ef06..d52332bbc76ac6f2d577fca317058ae375cdaf9f 100644 (file)
@@ -19,9 +19,9 @@
  */
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 import { formatMeasure } from '../../../helpers/measures';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 // Do not display the pending time for values smaller than this threshold (in ms)
 const MIN_PENDING_TIME_THRESHOLD = 1000;
index 295b25a435a35fd8fc634f17786f9911af76aeb2..cd70916cb7956bbcb7cd0fce025b782fad7c2015 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { HelperHintIcon, StandoutLink } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 export interface Props {
   failingCount?: number;
index 987f4786e52fe5c5c68788d41f033f2693e09530..7369ce40e2742f2e69e8693d6d29b1c603c03c5c 100644 (file)
@@ -26,9 +26,9 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import { getWorkers } from '../../../api/ce';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import Tooltip from '../../../components/controls/Tooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import NoWorkersSupportPopup from './NoWorkersSupportPopup';
 import WorkersForm from './WorkersForm';
 
index feea2774bad2595c14dc11a5372db613f1a17311..d62f224316e1ee09a0923a0e9c3b1df19fab3647 100644 (file)
@@ -30,7 +30,6 @@ import { difference, intersection } from 'lodash';
 import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import A11ySkipTarget from '../../../components/a11y/A11ySkipTarget';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import ListFooter from '../../../components/controls/ListFooter';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { Location } from '../../../components/hoc/withRouter';
@@ -39,6 +38,7 @@ import { CCT_SOFTWARE_QUALITY_METRICS, OLD_TAXONOMY_METRICS } from '../../../hel
 import { KeyboardKeys } from '../../../helpers/keycodes';
 import { translate } from '../../../helpers/l10n';
 import { areCCTMeasuresComputed } from '../../../helpers/measures';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike } from '../../../types/branch-like';
 import { isApplication, isPortfolioLike } from '../../../types/component';
 import { Breadcrumb, Component, ComponentMeasure, Dict, Metric } from '../../../types/types';
index 83e78403bd583b6ec5a40391387c831c66701906..5f17719be4e213f9a420f8eb26bc328a5d13156d 100644 (file)
@@ -22,8 +22,8 @@ import { FacetBox, FacetItem, HelperHintIcon, Note, themeColor } from 'design-sy
 import { sortBy } from 'lodash';
 import * as React from 'react';
 import { Profile } from '../../../api/quality-profiles';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { Dict } from '../../../types/types';
 import { FacetItemsList } from '../../issues/sidebar/FacetItemsList';
 import { FacetKey, Query } from '../query';
@@ -175,7 +175,7 @@ export default class ProfileFacet extends React.PureComponent<Props> {
         clearIconLabel={translate('clear')}
         count={count}
         help={
-          <DocumentationTooltip
+          <DocHelpTooltip
             content={translate('coding_rules.facet.qprofile.help')}
             links={[
               {
@@ -185,7 +185,7 @@ export default class ProfileFacet extends React.PureComponent<Props> {
             ]}
           >
             <HelperHintIcon />
-          </DocumentationTooltip>
+          </DocHelpTooltip>
         }
       >
         {open && (
index 03e7e4ef504689c062059588e572eae893be30c7..d6db414460f6569f95622d361eb956eb99b54491 100644 (file)
@@ -30,7 +30,6 @@ import {
 import * as React from 'react';
 import { Profile } from '../../../api/quality-profiles';
 import ConfirmButton from '../../../components/controls/ConfirmButton';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import DateFormatter from '../../../components/intl/DateFormatter';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import {
@@ -38,6 +37,7 @@ import {
   useRuleDetailsQuery,
   useUpdateRuleMutation,
 } from '../../../queries/rules';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Dict } from '../../../types/types';
 import { Activation } from '../query';
 import CustomRuleButton from './CustomRuleButton';
index 9c6971a7e4024b53eac24fbe430618393fa221bd..2437e4905a05a2de5e30c340a9dcd0b58310deb9 100644 (file)
  */
 import { Note, SeparatorCircleIcon, TextSubdued } from 'design-system';
 import * as React from 'react';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import IssueSeverityIcon from '../../../components/icon-mappers/IssueSeverityIcon';
 import IssueTypeIcon from '../../../components/icon-mappers/IssueTypeIcon';
 import TagsList from '../../../components/tags/TagsList';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { IssueSeverity } from '../../../types/issues';
 import { Dict, RuleDetails } from '../../../types/types';
 import RuleDetailsTagsPopup from './RuleDetailsTagsPopup';
@@ -44,7 +44,7 @@ export default function RuleDetailsHeaderActions(props: Readonly<Props>) {
   return (
     <Note className="sw-flex sw-flex-wrap sw-items-center sw-gap-2 sw-body-xs">
       {/* Type */}
-      <DocumentationTooltip
+      <DocHelpTooltip
         content={
           <>
             <p className="sw-mb-4">{translate('coding_rules.type.deprecation.title')}</p>
@@ -71,11 +71,11 @@ export default function RuleDetailsHeaderActions(props: Readonly<Props>) {
           />
           {translate('issue.type', ruleDetails.type)}
         </TextSubdued>
-      </DocumentationTooltip>
+      </DocHelpTooltip>
       <SeparatorCircleIcon />
 
       {/* Severity */}
-      <DocumentationTooltip
+      <DocHelpTooltip
         content={
           <>
             <p className="sw-mb-4">{translate('coding_rules.severity.deprecation.title')}</p>
@@ -102,7 +102,7 @@ export default function RuleDetailsHeaderActions(props: Readonly<Props>) {
           />
           {translate('severity', ruleDetails.severity)}
         </TextSubdued>
-      </DocumentationTooltip>
+      </DocHelpTooltip>
       <SeparatorCircleIcon />
 
       {/* Tags */}
index a60a0e5b927a66a7a1433badd037d2486c67caf6..203f4826d5e022dc119e405a997d53c4316a5bed 100644 (file)
  */
 import { Badge, HelperHintIcon, Link, Note, SeparatorCircleIcon } from 'design-system';
 import React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import Tooltip from '../../../components/controls/Tooltip';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getRuleUrl } from '../../../helpers/urls';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Dict, RuleDetails } from '../../../types/types';
 
 const EXTERNAL_RULE_REPO_PREFIX = 'external_';
index eab02e846c3540680568e683fdd08ce3d4417cfe..c5b9bdde608a57a040be41e6a354f06993fb21c0 100644 (file)
@@ -30,7 +30,6 @@ import {
 } from 'design-system';
 import * as React from 'react';
 import { Profile, deactivateRule } from '../../../api/quality-profiles';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import ConfirmButton from '../../../components/controls/ConfirmButton';
 import Tooltip from '../../../components/controls/Tooltip';
 import { CleanCodeAttributePill } from '../../../components/shared/CleanCodeAttributePill';
@@ -39,6 +38,7 @@ import TypeHelper from '../../../components/shared/TypeHelper';
 import TagsList from '../../../components/tags/TagsList';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getRuleUrl } from '../../../helpers/urls';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { Rule } from '../../../types/types';
 import { Activation } from '../query';
 import ActivationButton from './ActivationButton';
@@ -245,7 +245,7 @@ export default class RuleListItem extends React.PureComponent<Props> {
 
               <SeparatorCircleIcon aria-hidden as="li" />
               <li>
-                <DocumentationTooltip
+                <DocHelpTooltip
                   content={
                     <div>
                       <p className="sw-mb-2">{translate('coding_rules.type.deprecation.title')}</p>
@@ -264,7 +264,7 @@ export default class RuleListItem extends React.PureComponent<Props> {
                     iconFill="iconTypeDisabled"
                     type={rule.type}
                   />
-                </DocumentationTooltip>
+                </DocHelpTooltip>
               </li>
 
               {rule.isTemplate && (
index da7cd21b1c17b650778764d26ce9e67d0773b4c0..9924f4ba39e9e8876f56b18ac9ee2657e134217f 100644 (file)
  */
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
 import { IMPACT_SEVERITIES } from '../../../helpers/constants';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import Facet, { BasicProps } from './Facet';
 
 export default function SeverityFacet(props: BasicProps) {
@@ -49,7 +49,7 @@ export default function SeverityFacet(props: BasicProps) {
       renderName={renderName}
       renderTextName={renderTextName}
       help={
-        <DocumentationTooltip
+        <DocHelpTooltip
           placement="right"
           content={
             <>
@@ -65,7 +65,7 @@ export default function SeverityFacet(props: BasicProps) {
           ]}
         >
           <HelperHintIcon />
-        </DocumentationTooltip>
+        </DocHelpTooltip>
       }
     />
   );
index d973a4f68475f70cbcd4f2e87d77ff87f95b1a60..ba3b7fbc37c0982b8af63621f86efdfd7bcfb0cd 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import Facet, { BasicProps } from './Facet';
 
 interface Props extends Omit<BasicProps, 'onChange' | 'values'> {
index 72b5e0bbdd74d26e6d0f2fb9ae808b59d2189bad..91285196104b03aa016ca33548eb59fb0866692c 100644 (file)
@@ -34,7 +34,6 @@ import { Helmet } from 'react-helmet-async';
 import { getMeasuresWithPeriod } from '../../../api/measures';
 import { getAllMetrics } from '../../../api/metrics';
 import { ComponentContext } from '../../../app/components/componentContext/ComponentContext';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import Suggestions from '../../../components/embed-docs-modal/Suggestions';
 import { Location, Router, withRouter } from '../../../components/hoc/withRouter';
 import { enhanceMeasure } from '../../../components/measure/utils';
@@ -44,6 +43,7 @@ import { getBranchLikeQuery, isPullRequest, isSameBranchLike } from '../../../he
 import { translate } from '../../../helpers/l10n';
 import { areLeakAndOverallCCTMeasuresComputed } from '../../../helpers/measures';
 import { WithBranchLikesProps, useBranchesQuery } from '../../../queries/branch';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { ComponentQualifier, isPortfolioLike } from '../../../types/component';
 import { MeasurePageView } from '../../../types/measures';
 import { MetricKey } from '../../../types/metrics';
index f307a7d6530f1bae7c9e82959d9a579a4c869733..28bee63698c2db2b24168b020ae6c6f01403c896 100644 (file)
@@ -27,7 +27,6 @@ import {
   themeColor,
 } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import {
   getLocalizedMetricDomain,
   getLocalizedMetricName,
@@ -37,6 +36,7 @@ import {
 import { formatMeasure, isDiffMetric } from '../../../helpers/measures';
 import { isDefined } from '../../../helpers/types';
 import { getComponentDrilldownUrl } from '../../../helpers/urls';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike } from '../../../types/branch-like';
 import { isProject, isView } from '../../../types/component';
 import { MetricKey } from '../../../types/metrics';
index 685e3c0d9c67118b88b7020bf4ae6692e856b760..2ed3904b2a3f7801837ce25909c0a0b135659b05 100644 (file)
@@ -25,7 +25,6 @@ import {
   SubnavigationSubheading,
 } from 'design-system';
 import React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import {
   getLocalizedCategoryMetricName,
   getLocalizedMetricDomain,
@@ -33,6 +32,7 @@ import {
   hasMessage,
   translate,
 } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { MeasureEnhanced } from '../../../types/types';
 import {
   addMeasureCategories,
index 5c91aa611a74fe556523d947ec82cfa333ef613a..935fe980209983388e63529163b2a23e0480ebd9 100644 (file)
@@ -32,9 +32,9 @@ import {
 import * as React from 'react';
 import withAppStateContext from '../../../app/components/app-state/withAppStateContext';
 import { Image } from '../../../components/common/Image';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 import { getCreateProjectModeLocation } from '../../../helpers/urls';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { AlmKeys } from '../../../types/alm-settings';
 import { AppState } from '../../../types/appstate';
 import { CreateProjectModes } from './types';
index ca5ddc08eba5e1cccfd8b276f4b8d11c887a47be..b1907d3579886b1b059c09b36a75fd70eff3bc9c 100644 (file)
  */
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import SoftwareImpactSeverityIcon from '../../../components/icon-mappers/SoftwareImpactSeverityIcon';
 import { IMPACT_SEVERITIES } from '../../../helpers/constants';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { SoftwareImpactSeverity } from '../../../types/clean-code-taxonomy';
 import { CommonProps, SimpleListStyleFacet } from './SimpleListStyleFacet';
 
@@ -43,7 +43,7 @@ export function SeverityFacet(props: Props) {
         <SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
       )}
       help={
-        <DocumentationTooltip
+        <DocHelpTooltip
           placement="right"
           content={
             <>
@@ -59,7 +59,7 @@ export function SeverityFacet(props: Props) {
           ]}
         >
           <HelperHintIcon />
-        </DocumentationTooltip>
+        </DocHelpTooltip>
       }
       {...rest}
     />
index 06580922a2d353fee85ab75d1145fe0bc49d8611..7f7ef16ebcd46b44c7f08a22dac1213d760daf8e 100644 (file)
@@ -19,9 +19,9 @@
  */
 import { HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import DateFromNow from '../../../components/intl/DateFromNow';
 import { translateWithParameters } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { ApplicationPeriod } from '../../../types/application';
 
 export interface ApplicationLeakPeriodInfoProps {
index 9932523ba057b32fa501a0ff86e75027d1cf3bad..481531aad9644c0138ac12a178989af3500fde8f 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { HelperHintIcon, LightGreyCardTitle, PageTitle } from 'design-system';
 import React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 export function QualityGateStatusTitle() {
   return (
index 89bf1fef0ecfac0335b7bf5a8e295c05919e46ff..56fd70b6516b1c8f9399a781e392a0a9496a9322 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { FlagMessage, HelperHintIcon } from 'design-system';
 import React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 export default function IgnoredConditionWarning() {
   return (
index 2cb03cfc314e1a2e4b40df05655bece482f7641c..45315610a8ab32e5eaebe64c9503706c4e4515f4 100644 (file)
@@ -20,7 +20,7 @@
 import { HelperHintIcon, LightPrimary, QualityGateIndicator, TextMuted } from 'design-system';
 import React from 'react';
 import { useIntl } from 'react-intl';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike } from '../../../types/branch-like';
 import { QualityGateStatusConditionEnhanced } from '../../../types/quality-gates';
 import { Component, Status } from '../../../types/types';
index 2e08b3488a9c7fb998ec4590dcba3448aab6a962..ce6891f530a9d0f403a1ead6c8d49845c7be0d5b 100644 (file)
@@ -20,8 +20,8 @@
 import { ContentCell, FlagMessage, HelperHintIcon, TableRow } from 'design-system';
 import * as React from 'react';
 import InstanceMessage from '../../../components/common/InstanceMessage';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Permission } from '../../../types/types';
 
 interface Props {
index b68f60da361a365e634e8bddffa3f3df60ef4b02..aaad8c6b7b3bfb48452f064d47f1db217c90da68 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { ContentCell, HelperHintIcon } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 interface Props {
   permission: {
index 5027286ccfe480a8a8b0d8e9bf84c26f9ed2cac5..20f766a362016465bc131ca6a7a98432493e1624 100644 (file)
@@ -19,9 +19,9 @@
  */
 import { ActionCell, ContentCell, HelperHintIcon, Table, TableRow } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { getBranchLikeKey } from '../../../helpers/branch-like';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike } from '../../../types/branch-like';
 import { Component } from '../../../types/types';
 import BranchLikeRow from './BranchLikeRow';
index dce0f7d4ef6b0582f8a114e367ede786ba82e997..ee171be74f5b2fbf604021232fb6919ea54503d1 100644 (file)
 import { HelperHintIcon, Spinner, Switch } from 'design-system';
 import * as React from 'react';
 import { useEffect } from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { isMainBranch } from '../../../helpers/branch-like';
 import { translate } from '../../../helpers/l10n';
 import { useExcludeFromPurgeMutation } from '../../../queries/branch';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Branch } from '../../../types/branch-like';
 import { Component } from '../../../types/types';
 
index 1aefa601e49509ab2c88b517955700f19cb75cf5..7eb6b2adf690fabe7ce2369c39015fc354775630 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { ClipboardIconButton, CodeSnippet, HelperHintIcon, SubHeading } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../../components/controls/HelpTooltip';
 import { translate } from '../../../../helpers/l10n';
+import HelpTooltip from '../../../../sonar-aligned/components/controls/HelpTooltip';
 
 interface MetaKeyProps {
   componentKey: string;
index fde87b3a979dea45869dbffc47272dc465a4973b..208a0e3ba22487fa91bb81ddfaf207e21bddb5e5 100644 (file)
@@ -37,12 +37,12 @@ import { FormattedMessage } from 'react-intl';
 import { OptionProps, components } from 'react-select';
 import A11ySkipTarget from '../../components/a11y/A11ySkipTarget';
 import DisableableSelectOption from '../../components/common/DisableableSelectOption';
-import HelpTooltip from '../../components/controls/HelpTooltip';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../helpers/l10n';
 import { isDiffMetric } from '../../helpers/measures';
 import { LabelValueSelectOption } from '../../helpers/search';
 import { getQualityGateUrl } from '../../helpers/urls';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { QualityGate } from '../../types/types';
 import BuiltInQualityGateBadge from '../quality-gates/components/BuiltInQualityGateBadge';
 import { USE_SYSTEM_DEFAULT } from './constants';
index 9b4128d882e1fe5ae2cc6e4718321fa6759b4b46..791fbddc4aa758c83ba7270dc89a49a3cf1fe2ec 100644 (file)
@@ -38,10 +38,10 @@ import * as React from 'react';
 import { Helmet } from 'react-helmet-async';
 import { Profile } from '../../api/quality-profiles';
 import A11ySkipTarget from '../../components/a11y/A11ySkipTarget';
-import HelpTooltip from '../../components/controls/HelpTooltip';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
 import { translate } from '../../helpers/l10n';
 import { getRulesUrl } from '../../helpers/urls';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { Component } from '../../types/types';
 import BuiltInQualityProfileBadge from '../quality-profiles/components/BuiltInQualityProfileBadge';
 import AddLanguageModal from './components/AddLanguageModal';
index cbc1a174a9d6fcbd716e27d96ad20da9c6645b78..88fdd770958c92a211a4268162f3f1ad846aef4f 100644 (file)
@@ -20,9 +20,9 @@
 import { FacetBox, FacetItem, HelperHintIcon, QualityGateIndicator } from 'design-system';
 import { without } from 'lodash';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 import { isDefined } from '../../../helpers/types';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { RawQuery, Status } from '../../../types/types';
 import { FacetItemsList } from '../../issues/sidebar/FacetItemsList';
 import { formatFacetStat } from '../../issues/utils';
index e6cf3d19f8f20f52238314e0146a26183061ac3f..e13d7e2a77ddd381b9a6723448bba725516f15a2 100644 (file)
@@ -33,9 +33,9 @@ import * as React from 'react';
 import { OptionProps, SingleValueProps, components } from 'react-select';
 import { Project } from '../../api/project-management';
 import withAppStateContext from '../../app/components/app-state/withAppStateContext';
-import HelpTooltip from '../../components/controls/HelpTooltip';
 import { translate } from '../../helpers/l10n';
 import { LabelValueSelectOption } from '../../helpers/search';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { AppState } from '../../types/appstate';
 import { Visibility } from '../../types/component';
 import BulkApplyTemplateModal from './BulkApplyTemplateModal';
index 3aae6feafeb7e7dec627c7add31a1f013c570ab9..4d523433faa6eee8648b4a506a5ed59b71e981ac 100644 (file)
@@ -22,9 +22,9 @@ import { HelperHintIcon, Highlight } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import withMetricsContext from '../../../app/components/metrics/withMetricsContext';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import { translate } from '../../../helpers/l10n';
 import { formatMeasure } from '../../../helpers/measures';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { MetricKey } from '../../../types/metrics';
 import { Condition, Dict, Metric } from '../../../types/types';
 import { getCaycConditionMetadata, getLocalizedMetricNameNoDiffMetric } from '../utils';
@@ -64,12 +64,12 @@ function CaycCondition({ condition, metric, metrics }: Readonly<Props>) {
               value: <Highlight>&nbsp;{formatMeasure(condition.error, metric.type)}</Highlight>,
             }}
           />
-          <DocumentationTooltip
+          <DocHelpTooltip
             className="sw-ml-2 sw-align-text-top"
             content={translate('quality_gates.conditions.cayc.threshold.hint')}
           >
             <HelperHintIcon />
-          </DocumentationTooltip>
+          </DocHelpTooltip>
         </StyledContentCell>
       )}
     </StyledItem>
index 259d754d95ea10e88476a2f1e42bf39e95e3969d..d5323fb8bf5ce54115c12facef462000ed5efa83 100644 (file)
@@ -36,10 +36,10 @@ import { FormattedMessage } from 'react-intl';
 import { useAvailableFeatures } from '../../../app/components/available-features/withAvailableFeatures';
 import { useMetrics } from '../../../app/components/metrics/withMetricsContext';
 import DocumentationLink from '../../../components/common/DocumentationLink';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import ModalButton, { ModalProps } from '../../../components/controls/ModalButton';
 import { useDocUrl } from '../../../helpers/docs';
 import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { Feature } from '../../../types/features';
 import { MetricKey } from '../../../types/metrics';
 import { CaycStatus, Condition as ConditionType, QualityGate } from '../../../types/types';
@@ -181,7 +181,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
             {translate('quality_gates.conditions')}
           </HeadingDark>
           {!qualityGate.isBuiltIn && (
-            <DocumentationTooltip
+            <DocHelpTooltip
               className="sw-ml-2"
               content={translate('quality_gates.conditions.help')}
               links={[
@@ -192,7 +192,7 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
               ]}
             >
               <HelperHintIcon />
-            </DocumentationTooltip>
+            </DocHelpTooltip>
           )}
           <Spinner loading={isFetching} className="sw-ml-4 sw-mt-1" />
         </div>
@@ -227,12 +227,12 @@ export default function Conditions({ qualityGate, isFetching }: Readonly<Props>)
           <div>
             <div className="sw-flex sw-items-center sw-gap-2 sw-mb-2">
               <HeadingDark as="h3">{translate('quality_gates.conditions.cayc')}</HeadingDark>
-              <DocumentationTooltip
+              <DocHelpTooltip
                 content={translate('quality_gates.conditions.cayc.hint')}
                 placement="right"
               >
                 <HelperHintIcon />
-              </DocumentationTooltip>
+              </DocHelpTooltip>
             </div>
 
             <HighlightedSection className="sw-p-0 sw-my-2 sw-w-3/4" id="cayc-highlight">
index ae76b6635f0aa701347e9ba47561e8d1233068d8..736d86f8b603b60593c02493e0a40cd90234a2ca 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { FlagMessage, HelperHintIcon, SubTitle } from 'design-system';
 import * as React from 'react';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { QualityGate } from '../../../types/types';
 import Conditions from './Conditions';
 import Projects from './Projects';
@@ -50,12 +50,9 @@ export function DetailsContent(props: DetailsContentProps) {
         <div className="sw-flex sw-flex-col">
           <SubTitle as="h3" className="sw-body-md-highlight">
             {translate('quality_gates.projects')}
-            <DocumentationTooltip
-              className="sw-ml-2"
-              content={translate('quality_gates.projects.help')}
-            >
+            <DocHelpTooltip className="sw-ml-2" content={translate('quality_gates.projects.help')}>
               <HelperHintIcon />
-            </DocumentationTooltip>
+            </DocHelpTooltip>
           </SubTitle>
 
           {qualityGate.isDefault ? (
index 77e4efe8365ac7bffd04255d0d1f260395572145..b7ee1f61cee10ded85c88a6237d5e433459e3128 100644 (file)
@@ -19,9 +19,9 @@
  */
 import { ButtonPrimary, HelperHintIcon, Title } from 'design-system';
 import * as React from 'react';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import ModalButton, { ModalProps } from '../../../components/controls/ModalButton';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import CreateQualityGateForm from './CreateQualityGateForm';
 
 interface Props {
@@ -54,7 +54,7 @@ export default function ListHeader({ canCreate }: Readonly<Props>) {
         <Title className="sw-flex sw-items-center sw-body-md-highlight sw-mb-0">
           {translate('quality_gates.page')}
         </Title>
-        <DocumentationTooltip
+        <DocHelpTooltip
           className="sw-ml-2"
           content={translate('quality_gates.help')}
           links={[
@@ -65,7 +65,7 @@ export default function ListHeader({ canCreate }: Readonly<Props>) {
           ]}
         >
           <HelperHintIcon />
-        </DocumentationTooltip>
+        </DocHelpTooltip>
       </div>
       {canCreate && <CreateQualityGateModal />}
     </div>
index 226c6e0ecec43f0ed732fcfc3c0b7bf5b4e44143..4e2a832175e2732e7b31a3be3c7003bff342a714 100644 (file)
@@ -33,10 +33,10 @@ import * as React from 'react';
 import { useEffect, useState } from 'react';
 import { getQualityProfile } from '../../../api/quality-profiles';
 import { searchRules } from '../../../api/rules';
-import DocumentationTooltip from '../../../components/common/DocumentationTooltip';
 import { translate } from '../../../helpers/l10n';
 import { isDefined } from '../../../helpers/types';
 import { getRulesUrl } from '../../../helpers/urls';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { CleanCodeAttributeCategory, SoftwareQuality } from '../../../types/clean-code-taxonomy';
 import { SearchRulesResponse } from '../../../types/coding-rules';
 import { RulesFacetName } from '../../../types/rules';
@@ -219,11 +219,11 @@ export default function ProfileRules({ profile }: Readonly<Props>) {
         {/* this user could potentially activate more rules if the profile was not built-in */}
         {/* in such cases it's better to show the button but disable it with a tooltip */}
         {actions.copy && profile.isBuiltIn && (
-          <DocumentationTooltip content={translate('quality_profiles.activate_more.help.built_in')}>
+          <DocHelpTooltip content={translate('quality_profiles.activate_more.help.built_in')}>
             <ButtonPrimary className="it__quality-profiles__activate-rules" disabled>
               {translate('quality_profiles.activate_more')}
             </ButtonPrimary>
-          </DocumentationTooltip>
+          </DocHelpTooltip>
         )}
       </div>
     </section>
index 59945d15aaeae7834eba240ea85d2d8b5af80ae5..19d831e57499a53425d99d8dd47d456bbfac1aa2 100644 (file)
@@ -20,9 +20,9 @@
 import { FlagMessage, HelperHintIcon, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
 import { getDeprecatedActiveRulesUrl } from '../../../helpers/urls';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 interface Props {
   activeDeprecatedRules: number;
index 3b6e43f84beeeb2c61f582cb969531252194c887..762d3f8228b6dd33bd39581e1f0d159f2c852bd6 100644 (file)
@@ -20,9 +20,9 @@
 import { FlagMessage, Link } from 'design-system';
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate, translateWithParameters } from '../../../helpers/l10n';
 import { getRulesUrl } from '../../../helpers/urls';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 
 interface Props {
   language: string;
index a0f2f4861e5c83ecf190f6f3cb269986f273ba74..11ce798c9f12d412f6ab66855b734fb0aa3dbf04 100644 (file)
@@ -21,7 +21,7 @@ import { ContentCell, FlagMessage, HelperHintIcon, Table, TableRow } from 'desig
 import { groupBy, pick, sortBy } from 'lodash';
 import * as React from 'react';
 import { useIntl } from 'react-intl';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Language } from '../../../types/languages';
 import { Dict } from '../../../types/types';
 import { Profile } from '../types';
index 3553fa6a9b0ca86b523cbd8dcc7570cff1e8d8c0..49b4badb0c24be652c996a39af51d6dd93bc1d93 100644 (file)
@@ -33,12 +33,12 @@ import {
 import * as React from 'react';
 import withComponentContext from '../../../app/components/componentContext/withComponentContext';
 import withCurrentUserContext from '../../../app/components/current-user/withCurrentUserContext';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import Tooltip from '../../../components/controls/Tooltip';
 import Measure from '../../../components/measure/Measure';
 import { PopupPlacement } from '../../../components/ui/popups';
 import { isBranch } from '../../../helpers/branch-like';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { BranchLike } from '../../../types/branch-like';
 import { ComponentContextShape } from '../../../types/component';
 import { MetricKey, MetricType } from '../../../types/metrics';
index f844a2df4d7b87d355ccaad8484fa2b4994125a7..82d220e413f3ae0418bbea3c7461c04e90601fe0 100644 (file)
@@ -19,9 +19,9 @@
  */
 import { BasicSeparator, ThirdPartyButton } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translateWithParameters } from '../../../helpers/l10n';
 import { getBaseUrl } from '../../../helpers/system';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { IdentityProvider } from '../../../types/types';
 
 interface Props {
index dca6a27b378b3c5702dec70a4d3b9b776fe3c81a..5320238478b91429e5be4a46dd3e0edc7ed9eb20 100644 (file)
@@ -30,11 +30,11 @@ import {
 import * as React from 'react';
 import { FormattedMessage } from 'react-intl';
 import DocumentationLink from '../../../../components/common/DocumentationLink';
-import HelpTooltip from '../../../../components/controls/HelpTooltip';
 import Tooltip from '../../../../components/controls/Tooltip';
 import { ALM_DOCUMENTATION_PATHS, IMPORT_COMPATIBLE_ALMS } from '../../../../helpers/constants';
 import { getEdition, getEditionUrl } from '../../../../helpers/editions';
 import { translate, translateWithParameters } from '../../../../helpers/l10n';
+import HelpTooltip from '../../../../sonar-aligned/components/controls/HelpTooltip';
 import {
   AlmBindingDefinitionBase,
   AlmKeys,
index 13c7b35368e1f9af5777688ae3cb80c5a4a180e4..dcb201407949081e2d568f2ab392400c820d278b 100644 (file)
@@ -32,7 +32,6 @@ import { Helmet } from 'react-helmet-async';
 import { getIdentityProviders } from '../../api/users';
 import GitHubSynchronisationWarning from '../../app/components/GitHubSynchronisationWarning';
 import GitLabSynchronisationWarning from '../../app/components/GitLabSynchronisationWarning';
-import HelpTooltip from '../../components/controls/HelpTooltip';
 import ListFooter from '../../components/controls/ListFooter';
 import { ManagedFilter } from '../../components/controls/ManagedFilter';
 import Suggestions from '../../components/embed-docs-modal/Suggestions';
@@ -41,6 +40,7 @@ import { translate } from '../../helpers/l10n';
 import { LabelValueSelectOption } from '../../helpers/search';
 import { useIdentityProviderQuery } from '../../queries/identity-provider/common';
 import { useUsersQueries } from '../../queries/users';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { IdentityProvider, Provider } from '../../types/types';
 import { RestUserDetailed } from '../../types/users';
 import Header from './Header';
index 19a2bb20dd6a2518dd3be12ddd07b74183771f85..38c6ad6fc403131c23ce83c37d971dc2fcba342a 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { ActionCell, ContentCell, HelperHintIcon, Table, TableRow } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../components/controls/HelpTooltip';
 import { translate } from '../../helpers/l10n';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { IdentityProvider, Provider } from '../../types/types';
 import { RestUserDetailed } from '../../types/users';
 import UserListItem from './components/UserListItem';
index dda53c788360180b1463dc6bd0a53cf00ca0aaa2..1d445d41e0204ed19fa45c8ec6dde9c12cef88e9 100644 (file)
@@ -32,8 +32,8 @@ import { sortBy } from 'lodash';
 import { OpenAPIV3 } from 'openapi-types';
 import React, { Fragment, useContext, useMemo, useState } from 'react';
 import { useLocation, useNavigate } from 'react-router-dom';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Dict } from '../../../types/types';
 import { InternalExtension } from '../types';
 import { URL_DIVIDER, getApiEndpointKey } from '../utils';
index be7bb705e7864c74f57b760a1774a11373d971f5..ec3be1f3c8735dcdda41062ce42e661fc1e84da7 100644 (file)
@@ -19,8 +19,8 @@
  */
 import { Checkbox, HelperHintIcon, InputSearch } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
 import { translate } from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
 import { Query } from '../utils';
 
 interface Props {
diff --git a/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx b/server/sonar-web/src/main/js/components/common/DocumentationTooltip.tsx
deleted file mode 100644 (file)
index 7fd645b..0000000
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * 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 { first, last } from 'lodash';
-import * as React from 'react';
-import HelpTooltip from '../../components/controls/HelpTooltip';
-import { KeyboardKeys } from '../../helpers/keycodes';
-import { Placement } from '../controls/Tooltip';
-import DocumentationLink from './DocumentationLink';
-import Link from './Link';
-
-export interface DocumentationTooltipProps {
-  children?: React.ReactNode;
-  className?: string;
-  placement?: Placement;
-  content?: React.ReactNode;
-  links?: Array<{ href: string; label: string; inPlace?: boolean; doc?: boolean }>;
-  title?: string;
-}
-
-export default function DocumentationTooltip(props: DocumentationTooltipProps) {
-  const nextSelectableNode = React.useRef<HTMLElement | undefined | null>();
-  const linksRef = React.useRef<Array<HTMLAnchorElement | null>>([]);
-  const helpRef = React.useRef<HTMLElement>(null);
-  const { className, children, content, links, title, placement } = props;
-
-  function handleShowTooltip() {
-    document.addEventListener('keydown', handleTabPress);
-  }
-
-  function handleHideTooltip() {
-    document.removeEventListener('keydown', handleTabPress);
-    nextSelectableNode.current = undefined;
-  }
-
-  function handleTabPress(event: KeyboardEvent) {
-    if (event.code === KeyboardKeys.Tab) {
-      if (event.shiftKey) {
-        if (event.target === first(linksRef.current)) {
-          helpRef.current?.focus();
-        }
-        return;
-      }
-      if (event.target === last(linksRef.current)) {
-        event.preventDefault();
-        nextSelectableNode.current?.focus();
-        return;
-      }
-      if (nextSelectableNode.current === undefined) {
-        nextSelectableNode.current = event.target as HTMLElement;
-        event.preventDefault();
-        linksRef.current[0]?.focus();
-      }
-    }
-  }
-
-  return (
-    <HelpTooltip
-      className={className}
-      onShow={handleShowTooltip}
-      onHide={handleHideTooltip}
-      placement={placement}
-      isInteractive
-      innerRef={helpRef}
-      overlay={
-        <div className="sw-py-4">
-          {title && (
-            <div className="sw-mb-2">
-              <strong>{title}</strong>
-            </div>
-          )}
-
-          {content && <div>{content}</div>}
-
-          {links && (
-            <>
-              <hr className="sw-my-4" />
-
-              {links.map(({ href, label, inPlace, doc = true }, index) => (
-                <div className="sw-mb-1" key={label}>
-                  {doc ? (
-                    <DocumentationLink
-                      to={href}
-                      innerRef={(ref) => (linksRef.current[index] = ref)}
-                    >
-                      {label}
-                    </DocumentationLink>
-                  ) : (
-                    <Link
-                      to={href}
-                      ref={(ref) => (linksRef.current[index] = ref)}
-                      target={inPlace ? undefined : '_blank'}
-                    >
-                      {label}
-                    </Link>
-                  )}
-                </div>
-              ))}
-            </>
-          )}
-        </div>
-      }
-    >
-      {children}
-    </HelpTooltip>
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx b/server/sonar-web/src/main/js/components/common/__tests__/DocumentationTooltip-test.tsx
deleted file mode 100644 (file)
index d6a721b..0000000
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * 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 userEvent from '@testing-library/user-event';
-import * as React from 'react';
-import { byRole, byTestId } from '../../../helpers/testSelector';
-
-import { renderComponent } from '../../../helpers/testReactTestingUtils';
-import DocumentationTooltip, { DocumentationTooltipProps } from '../DocumentationTooltip';
-import Link from '../Link';
-
-const ui = {
-  body: byRole('body'),
-  beforeLink: byRole('link', { name: 'Interactive element before' }),
-  helpIcon: byTestId('help-tooltip-activator'),
-  helpLink: byRole('link', { name: 'Icon' }),
-  linkInTooltip: byRole('link', { name: 'Label' }),
-  linkInTooltip2: byRole('link', { name: 'Label2' }),
-  afterLink: byRole('link', { name: 'Interactive element after' }),
-};
-
-it('should correctly navigate through TAB', async () => {
-  const user = userEvent.setup();
-  renderDocumentationTooltip();
-
-  await user.tab();
-  expect(await ui.beforeLink.find()).toHaveFocus();
-  await user.tab();
-  expect(ui.helpIcon.get()).toHaveFocus();
-  await user.tab();
-  expect(ui.linkInTooltip.get()).toHaveFocus();
-  await user.tab();
-  expect(ui.linkInTooltip2.get()).toHaveFocus();
-  // Looks like RTL tab event ignores any custom focuses during the events phase,
-  // unless preventDefault is specified
-  await user.tab();
-  expect(ui.helpIcon.get()).toHaveFocus();
-  await user.tab({ shift: true });
-  await user.tab({ shift: true });
-  await user.tab();
-  await user.tab();
-  await user.tab({ shift: true });
-  expect(await ui.beforeLink.find()).toHaveFocus();
-});
-
-function renderDocumentationTooltip(props: Partial<DocumentationTooltipProps> = {}) {
-  return renderComponent(
-    <>
-      <Link to="/" target="_blank">
-        Interactive element before
-      </Link>
-      <DocumentationTooltip
-        title="Tooltip title"
-        content="Tooltip content"
-        links={[
-          {
-            href: '/user-guide/clean-as-you-code/',
-            label: 'Label',
-            doc: false,
-          },
-          {
-            href: '/user-guide/clean-as-you-code2/',
-            label: 'Label2',
-            doc: true,
-            inPlace: true,
-          },
-        ]}
-        {...props}
-      >
-        <Link to="/" target="_blank">
-          Icon
-        </Link>
-      </DocumentationTooltip>
-      <Link to="/" target="_blank">
-        Interactive element after
-      </Link>
-    </>,
-  );
-}
diff --git a/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx b/server/sonar-web/src/main/js/components/controls/HelpTooltip.tsx
deleted file mode 100644 (file)
index 1105fef..0000000
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * 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 classNames from 'classnames';
-import { HelperHintIcon } from 'design-system';
-import * as React from 'react';
-import { translate } from '../../helpers/l10n';
-import Tooltip, { Placement } from './Tooltip';
-
-interface Props {
-  className?: string;
-  children?: React.ReactNode;
-  onShow?: () => void;
-  onHide?: () => void;
-  overlay: React.ReactNode;
-  placement?: Placement;
-  isInteractive?: boolean;
-  innerRef?: React.Ref<HTMLSpanElement>;
-  size?: number;
-}
-
-const DEFAULT_SIZE = 12;
-
-export default function HelpTooltip(props: Props) {
-  const { size = DEFAULT_SIZE, overlay, placement, isInteractive, innerRef, children } = props;
-  return (
-    <div
-      className={classNames(
-        'it__help-tooltip sw-inline-flex sw-items-center sw-align-middle',
-        props.className,
-      )}
-    >
-      <Tooltip
-        mouseLeaveDelay={0.25}
-        onShow={props.onShow}
-        onHide={props.onHide}
-        overlay={overlay}
-        placement={placement}
-        isInteractive={isInteractive}
-      >
-        <span
-          className="sw-inline-flex sw-items-center"
-          data-testid="help-tooltip-activator"
-          ref={innerRef}
-        >
-          {children ?? (
-            <HelperHintIcon
-              aria-label={isInteractive ? translate('tooltip_is_interactive') : translate('help')}
-              description={
-                isInteractive ? (
-                  <>
-                    {translate('tooltip_is_interactive')}
-                    {overlay}
-                  </>
-                ) : (
-                  overlay
-                )
-              }
-              height={size}
-              width={size}
-            />
-          )}
-        </span>
-      </Tooltip>
-    </div>
-  );
-}
index 4119d20a857e7f149ce76f2a37ad00bab9418a6c..a9b2ab472debf055bb97fc841743b4fb6f60e063 100644 (file)
@@ -43,7 +43,7 @@ export interface TooltipProps {
   visible?: boolean;
   // If tooltip overlay has interactive content (links for instance) we may set this to true to stop
   // default behavior of tabbing (other changes should be done outside of this component to make it work)
-  // See example DocumentationTooltip
+  // See example DocHelpTooltip
   isInteractive?: boolean;
   classNameInner?: string;
 }
index 632e595bfae0a0e02a1cc8f812ff5481c9922e4a..6097ec405e88445e2d91039963f93db13bc33ddc 100644 (file)
@@ -21,9 +21,9 @@
 import { IconProps, TextSubdued } from 'design-system';
 import * as React from 'react';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { IssueSeverity as IssueSeverityType } from '../../../types/issues';
 import { Issue } from '../../../types/types';
-import DocumentationTooltip from '../../common/DocumentationTooltip';
 import IssueSeverityIcon from '../../icon-mappers/IssueSeverityIcon';
 import { DeprecatedFieldTooltip } from './DeprecatedFieldTooltip';
 
@@ -33,7 +33,7 @@ interface Props extends IconProps {
 
 export default function IssueSeverity({ issue, ...iconProps }: Readonly<Props>) {
   return (
-    <DocumentationTooltip
+    <DocHelpTooltip
       content={<DeprecatedFieldTooltip field="severity" />}
       links={[
         {
@@ -51,6 +51,6 @@ export default function IssueSeverity({ issue, ...iconProps }: Readonly<Props>)
         />
         {translate('severity', issue.severity)}
       </TextSubdued>
-    </DocumentationTooltip>
+    </DocHelpTooltip>
   );
 }
index fca4bc1cc81ae6ea0866c40285b40ffa5b5ef024..cf04cc0553d9cf189d347fa563417dfa07d53a91 100644 (file)
@@ -21,8 +21,8 @@
 import { IconProps, TextSubdued } from 'design-system';
 import * as React from 'react';
 import { translate } from '../../../helpers/l10n';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { Issue } from '../../../types/types';
-import DocumentationTooltip from '../../common/DocumentationTooltip';
 import IssueTypeIcon from '../../icon-mappers/IssueTypeIcon';
 import { DeprecatedFieldTooltip } from './DeprecatedFieldTooltip';
 
@@ -32,7 +32,7 @@ interface Props extends IconProps {
 
 export default function IssueType({ issue, ...iconProps }: Readonly<Props>) {
   return (
-    <DocumentationTooltip
+    <DocHelpTooltip
       content={<DeprecatedFieldTooltip field="type" />}
       links={[
         {
@@ -45,6 +45,6 @@ export default function IssueType({ issue, ...iconProps }: Readonly<Props>) {
         <IssueTypeIcon fill="iconTypeDisabled" type={issue.type} aria-hidden {...iconProps} />
         {translate('issue.type', issue.type)}
       </TextSubdued>
-    </DocumentationTooltip>
+    </DocHelpTooltip>
   );
 }
index 0d39147668b8e4760da67717b01c5ad2b1ab7543..45ffe96701486e9469b228117a3412aff50ffdfb 100644 (file)
@@ -22,10 +22,10 @@ import { BareButton, ContentCell, HelperHintIcon } from 'design-system';
 import * as React from 'react';
 import { translate, translateWithParameters } from '../../helpers/l10n';
 import { isPermissionDefinitionGroup } from '../../helpers/permissions';
+import HelpTooltip from '../../sonar-aligned/components/controls/HelpTooltip';
 import { PermissionDefinition, PermissionDefinitionGroup } from '../../types/types';
 import InstanceMessage from '../common/InstanceMessage';
 import ClickEventBoundary from '../controls/ClickEventBoundary';
-import HelpTooltip from '../controls/HelpTooltip';
 import Tooltip from '../controls/Tooltip';
 
 interface Props {
index b8c20b40ae18b3d2b064373b3f3d23dbbf028459..da66a71b98e833568ace56aca6a04cf4b2a1c0f0 100644 (file)
@@ -20,8 +20,8 @@
 import { Pill } from 'design-system';
 import React from 'react';
 import { translate } from '../../helpers/l10n';
+import DocHelpTooltip from '../../sonar-aligned/components/controls/DocHelpTooltip';
 import { CleanCodeAttribute, CleanCodeAttributeCategory } from '../../types/clean-code-taxonomy';
-import DocumentationTooltip from '../common/DocumentationTooltip';
 
 export interface Props {
   className?: string;
@@ -34,7 +34,7 @@ export function CleanCodeAttributePill(props: Readonly<Props>) {
   const { className, cleanCodeAttributeCategory, cleanCodeAttribute, type = 'issue' } = props;
 
   return (
-    <DocumentationTooltip
+    <DocHelpTooltip
       content={
         <>
           <p className="sw-mb-4">
@@ -70,6 +70,6 @@ export function CleanCodeAttributePill(props: Readonly<Props>) {
           <span> | {translate(type, 'clean_code_attribute', cleanCodeAttribute)}</span>
         )}
       </Pill>
-    </DocumentationTooltip>
+    </DocHelpTooltip>
   );
 }
index d4dca929885a9a6bd85369ed5dfe1f5cdadf1a4a..916b273662709b830a99451e51386a33ebf163d4 100644 (file)
@@ -22,8 +22,8 @@ import { Pill } from 'design-system';
 import React from 'react';
 import { FormattedMessage } from 'react-intl';
 import { translate } from '../../helpers/l10n';
+import DocHelpTooltip from '../../sonar-aligned/components/controls/DocHelpTooltip';
 import { SoftwareImpactSeverity } from '../../types/clean-code-taxonomy';
-import DocumentationTooltip from '../common/DocumentationTooltip';
 import SoftwareImpactSeverityIcon from '../icon-mappers/SoftwareImpactSeverityIcon';
 
 export interface Props {
@@ -43,7 +43,7 @@ export default function SoftwareImpactPill(props: Props) {
   }[severity] as 'danger' | 'warning' | 'info';
 
   return (
-    <DocumentationTooltip
+    <DocHelpTooltip
       content={
         <FormattedMessage
           id={`${type}.impact.severity.tooltip`}
@@ -65,6 +65,6 @@ export default function SoftwareImpactPill(props: Props) {
         {quality}
         <SoftwareImpactSeverityIcon severity={severity} data-guiding-id="issue-3" />
       </Pill>
-    </DocumentationTooltip>
+    </DocHelpTooltip>
   );
 }
index fc59e061889d0b48867efbf2465e24b9092eeb84..84b70ae1789357f25cdbb6647e70b5b39daf3500 100644 (file)
@@ -19,7 +19,7 @@
  */
 import { CodeSnippet, FlagMessage, HelperHintIcon, NumberedListItem } from 'design-system';
 import * as React from 'react';
-import HelpTooltip from '../../../../components/controls/HelpTooltip';
+import HelpTooltip from '../../../../sonar-aligned/components/controls/HelpTooltip';
 import SentenceWithFilename from '../../components/SentenceWithFilename';
 import SentenceWithHighlights from '../../components/SentenceWithHighlights';
 
index 4349810a5fd03fa24444d6ad9c790e071e58950c..675a4801c031445d9a559841f19667b8baae5051 100644 (file)
@@ -48,9 +48,9 @@ import {
   computeTokenExpirationDate,
   getAvailableExpirationOptions,
 } from '../../../helpers/tokens';
+import DocHelpTooltip from '../../../sonar-aligned/components/controls/DocHelpTooltip';
 import { TokenExpiration, TokenType, UserToken } from '../../../types/token';
 import { LoggedInUser } from '../../../types/users';
-import DocumentationTooltip from '../../common/DocumentationTooltip';
 import ProjectTokenScopeInfo from '../components/ProjectTokenScopeInfo';
 import Step from '../components/Step';
 import { getUniqueTokenName } from '../utils';
@@ -213,7 +213,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
           <div className="sw-flex sw-flex-col">
             <HighlightLabel className="sw-mb-2" htmlFor="generate-token-input">
               {translate('onboarding.token.name.label')}
-              <DocumentationTooltip
+              <DocHelpTooltip
                 className="sw-ml-2"
                 content={translate('onboarding.token.name.help')}
                 links={[
@@ -224,7 +224,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
                 ]}
               >
                 <HelperHintIcon />
-              </DocumentationTooltip>
+              </DocHelpTooltip>
             </HighlightLabel>
             <InputField
               id="generate-token-input"
@@ -276,7 +276,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
           <div className="sw-flex sw-flex-col sw-mt-4">
             <HighlightLabel className="sw-mb-2" htmlFor="existing-token-input">
               {translate('onboarding.token.use_existing_token.label')}
-              <DocumentationTooltip
+              <DocHelpTooltip
                 className="sw-ml-2"
                 content={translate('onboarding.token.use_existing_token.help')}
                 links={[
@@ -287,7 +287,7 @@ export default class TokenStep extends React.PureComponent<Props, State> {
                 ]}
               >
                 <HelperHintIcon />
-              </DocumentationTooltip>
+              </DocHelpTooltip>
             </HighlightLabel>
             <InputField
               id="existing-token-input"
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/DocHelpTooltip.tsx
new file mode 100644 (file)
index 0000000..8454f7c
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * 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 classNames from 'classnames';
+import { HelperHintIcon } from 'design-system';
+import { first, last } from 'lodash';
+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 { KeyboardKeys } from '../../../helpers/keycodes';
+import { translate } from '../../../helpers/l10n';
+
+export interface DocHelpTooltipProps {
+  children?: React.ReactNode;
+  className?: string;
+  content?: React.ReactNode;
+  linkTextLabel?: string;
+  links?: Array<{ href: string; label?: string; inPlace?: boolean; doc?: boolean }>;
+  placement?: Placement;
+  title?: string;
+}
+
+export default function DocHelpTooltip(props: Readonly<DocHelpTooltipProps>) {
+  const nextSelectableNode = React.useRef<HTMLElement | undefined | null>();
+  const linksRef = React.useRef<Array<HTMLAnchorElement | null>>([]);
+  const helpRef = React.useRef<HTMLElement>(null);
+  const { className, children, content, links, title, placement, linkTextLabel } = props;
+
+  function handleShowTooltip() {
+    document.addEventListener('keydown', handleTabPress);
+  }
+
+  function handleHideTooltip() {
+    document.removeEventListener('keydown', handleTabPress);
+    nextSelectableNode.current = undefined;
+  }
+
+  function handleTabPress(event: KeyboardEvent) {
+    if (event.code === KeyboardKeys.Tab) {
+      if (event.shiftKey) {
+        if (event.target === first(linksRef.current)) {
+          helpRef.current?.focus();
+        }
+        return;
+      }
+      if (event.target === last(linksRef.current)) {
+        event.preventDefault();
+        nextSelectableNode.current?.focus();
+        return;
+      }
+      if (nextSelectableNode.current === undefined) {
+        nextSelectableNode.current = event.target as HTMLElement;
+        event.preventDefault();
+        linksRef.current[0]?.focus();
+      }
+    }
+  }
+
+  const overlay = (
+    <div className="sw-py-4">
+      {title !== undefined && (
+        <div className="sw-mb-2">
+          <strong>{title}</strong>
+        </div>
+      )}
+
+      {content && <div>{content}</div>}
+
+      {links && (
+        <>
+          <hr className="sw-my-4" />
+
+          {links.map(({ href, label = translate('learn_more'), inPlace, doc = true }, index) => (
+            <div className="sw-mb-1" key={label}>
+              {index === 0 && linkTextLabel && `${linkTextLabel}: `}
+              {doc ? (
+                <DocumentationLink to={href} innerRef={(ref) => (linksRef.current[index] = ref)}>
+                  {label}
+                </DocumentationLink>
+              ) : (
+                <Link
+                  to={href}
+                  ref={(ref) => (linksRef.current[index] = ref)}
+                  target={inPlace ? undefined : '_blank'}
+                >
+                  {label}
+                </Link>
+              )}
+            </div>
+          ))}
+        </>
+      )}
+    </div>
+  );
+
+  return (
+    <div
+      className={classNames(
+        'it__help-tooltip sw-inline-flex sw-items-center sw-align-middle',
+        className,
+      )}
+    >
+      <Tooltip
+        mouseLeaveDelay={0.25}
+        onShow={handleShowTooltip}
+        onHide={handleHideTooltip}
+        overlay={overlay}
+        placement={placement}
+        isInteractive
+      >
+        <span
+          className="sw-inline-flex sw-items-center"
+          data-testid="help-tooltip-activator"
+          ref={helpRef}
+        >
+          {children ?? (
+            <HelperHintIcon
+              aria-label={translate('tooltip_is_interactive')}
+              description={
+                <>
+                  {translate('tooltip_is_interactive')}
+                  {overlay}
+                </>
+              }
+            />
+          )}
+        </span>
+      </Tooltip>
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/HelpTooltip.tsx
new file mode 100644 (file)
index 0000000..5b62130
--- /dev/null
@@ -0,0 +1,64 @@
+/*
+ * 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 classNames from 'classnames';
+import { HelperHintIcon } from 'design-system';
+import * as React from 'react';
+import Tooltip, { Placement } from '../../../components/controls/Tooltip';
+import { translate } from '../../../helpers/l10n';
+
+interface Props {
+  'aria-label'?: string;
+  children?: React.ReactNode;
+  className?: string;
+  'data-testid'?: string;
+  overlay: React.ReactNode;
+  placement?: Placement;
+}
+
+const DEFAULT_SIZE = 12;
+
+export default function HelpTooltip(props: Readonly<Props>) {
+  const { overlay, placement, children } = props;
+  return (
+    <div
+      className={classNames(
+        'it__help-tooltip sw-inline-flex sw-items-center sw-align-middle',
+        props.className,
+      )}
+    >
+      <Tooltip mouseLeaveDelay={0.25} overlay={overlay} placement={placement}>
+        <span
+          aria-label={props['aria-label']}
+          className="sw-inline-flex sw-items-center"
+          data-testid={props['data-testid'] ?? 'help-tooltip-activator'}
+        >
+          {children ?? (
+            <HelperHintIcon
+              aria-label={translate('help')}
+              description={overlay}
+              height={DEFAULT_SIZE}
+              width={DEFAULT_SIZE}
+            />
+          )}
+        </span>
+      </Tooltip>
+    </div>
+  );
+}
diff --git a/server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx b/server/sonar-web/src/main/js/sonar-aligned/components/controls/__tests__/DocHelpTooltip-test.tsx
new file mode 100644 (file)
index 0000000..691d25f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * 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 userEvent from '@testing-library/user-event';
+import * as React from 'react';
+import { byRole, byTestId } from '../../../../helpers/testSelector';
+
+import Link from '../../../../components/common/Link';
+import { renderComponent } from '../../../../helpers/testReactTestingUtils';
+import DocHelpTooltip, { DocHelpTooltipProps } from '../DocHelpTooltip';
+
+const ui = {
+  body: byRole('body'),
+  beforeLink: byRole('link', { name: 'Interactive element before' }),
+  helpIcon: byTestId('help-tooltip-activator'),
+  helpLink: byRole('link', { name: 'Icon' }),
+  linkInTooltip: byRole('link', { name: 'Label' }),
+  linkInTooltip2: byRole('link', { name: 'Label2' }),
+  afterLink: byRole('link', { name: 'Interactive element after' }),
+};
+
+it('should correctly navigate through TAB', async () => {
+  const user = userEvent.setup();
+  renderDocHelpTooltip();
+
+  await user.tab();
+  expect(await ui.beforeLink.find()).toHaveFocus();
+  await user.tab();
+  expect(ui.helpIcon.get()).toHaveFocus();
+  await user.tab();
+  expect(ui.linkInTooltip.get()).toHaveFocus();
+  await user.tab();
+  expect(ui.linkInTooltip2.get()).toHaveFocus();
+  // Looks like RTL tab event ignores any custom focuses during the events phase,
+  // unless preventDefault is specified
+  await user.tab();
+  expect(ui.helpIcon.get()).toHaveFocus();
+  await user.tab({ shift: true });
+  await user.tab({ shift: true });
+  await user.tab();
+  await user.tab();
+  await user.tab({ shift: true });
+  expect(await ui.beforeLink.find()).toHaveFocus();
+});
+
+function renderDocHelpTooltip(props: Partial<DocHelpTooltipProps> = {}) {
+  return renderComponent(
+    <>
+      <Link to="/" target="_blank">
+        Interactive element before
+      </Link>
+      <DocHelpTooltip
+        title="Tooltip title"
+        content="Tooltip content"
+        links={[
+          {
+            href: '/user-guide/clean-as-you-code/',
+            label: 'Label',
+            doc: false,
+          },
+          {
+            href: '/user-guide/clean-as-you-code2/',
+            label: 'Label2',
+            doc: true,
+            inPlace: true,
+          },
+        ]}
+        {...props}
+      >
+        <Link to="/" target="_blank">
+          Icon
+        </Link>
+      </DocHelpTooltip>
+      <Link to="/" target="_blank">
+        Interactive element after
+      </Link>
+    </>,
+  );
+}