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';
} else {
if (!branchSupportEnabled) {
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={
projectBinding != null
? translateWithParameters(
}
>
{helpIcon}
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
if (!hasManyBranches) {
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={translate('branch_like_navigation.only_one_branch.content')}
data-test="only-one-branch-like"
links={[
title={translate('branch_like_navigation.only_one_branch.title')}
>
{helpIcon}
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
}
*/
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';
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';
*/
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;
*/
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;
} 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';
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';
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';
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';
clearIconLabel={translate('clear')}
count={count}
help={
- <DocumentationTooltip
+ <DocHelpTooltip
content={translate('coding_rules.facet.qprofile.help')}
links={[
{
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
}
>
{open && (
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 {
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';
*/
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';
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>
/>
{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>
/>
{translate('severity', ruleDetails.severity)}
</TextSubdued>
- </DocumentationTooltip>
+ </DocHelpTooltip>
<SeparatorCircleIcon />
{/* Tags */}
*/
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_';
} 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';
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';
<SeparatorCircleIcon aria-hidden as="li" />
<li>
- <DocumentationTooltip
+ <DocHelpTooltip
content={
<div>
<p className="sw-mb-2">{translate('coding_rules.type.deprecation.title')}</p>
iconFill="iconTypeDisabled"
type={rule.type}
/>
- </DocumentationTooltip>
+ </DocHelpTooltip>
</li>
{rule.isTemplate && (
*/
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) {
renderName={renderName}
renderTextName={renderTextName}
help={
- <DocumentationTooltip
+ <DocHelpTooltip
placement="right"
content={
<>
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
}
/>
);
*/
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'> {
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';
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';
themeColor,
} from 'design-system';
import * as React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
import {
getLocalizedMetricDomain,
getLocalizedMetricName,
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';
SubnavigationSubheading,
} from 'design-system';
import React from 'react';
-import HelpTooltip from '../../../components/controls/HelpTooltip';
import {
getLocalizedCategoryMetricName,
getLocalizedMetricDomain,
hasMessage,
translate,
} from '../../../helpers/l10n';
+import HelpTooltip from '../../../sonar-aligned/components/controls/HelpTooltip';
import { MeasureEnhanced } from '../../../types/types';
import {
addMeasureCategories,
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';
*/
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';
<SoftwareImpactSeverityIcon severity={severity} disabled={disabled} />
)}
help={
- <DocumentationTooltip
+ <DocHelpTooltip
placement="right"
content={
<>
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
}
{...rest}
/>
*/
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 {
*/
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 (
*/
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 (
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';
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 {
*/
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: {
*/
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';
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';
*/
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;
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';
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';
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';
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';
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';
value: <Highlight> {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>
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';
{translate('quality_gates.conditions')}
</HeadingDark>
{!qualityGate.isBuiltIn && (
- <DocumentationTooltip
+ <DocHelpTooltip
className="sw-ml-2"
content={translate('quality_gates.conditions.help')}
links={[
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
)}
<Spinner loading={isFetching} className="sw-ml-4 sw-mt-1" />
</div>
<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">
*/
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';
<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 ? (
*/
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 {
<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={[
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
</div>
{canCreate && <CreateQualityGateModal />}
</div>
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';
{/* 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>
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;
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;
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';
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';
*/
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 {
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,
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';
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';
*/
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';
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';
*/
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 {
+++ /dev/null
-/*
- * 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>
- );
-}
+++ /dev/null
-/*
- * 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>
- </>,
- );
-}
+++ /dev/null
-/*
- * 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>
- );
-}
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;
}
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';
export default function IssueSeverity({ issue, ...iconProps }: Readonly<Props>) {
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={<DeprecatedFieldTooltip field="severity" />}
links={[
{
/>
{translate('severity', issue.severity)}
</TextSubdued>
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
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';
export default function IssueType({ issue, ...iconProps }: Readonly<Props>) {
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={<DeprecatedFieldTooltip field="type" />}
links={[
{
<IssueTypeIcon fill="iconTypeDisabled" type={issue.type} aria-hidden {...iconProps} />
{translate('issue.type', issue.type)}
</TextSubdued>
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
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 {
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;
const { className, cleanCodeAttributeCategory, cleanCodeAttribute, type = 'issue' } = props;
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={
<>
<p className="sw-mb-4">
<span> | {translate(type, 'clean_code_attribute', cleanCodeAttribute)}</span>
)}
</Pill>
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
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 {
}[severity] as 'danger' | 'warning' | 'info';
return (
- <DocumentationTooltip
+ <DocHelpTooltip
content={
<FormattedMessage
id={`${type}.impact.severity.tooltip`}
{quality}
<SoftwareImpactSeverityIcon severity={severity} data-guiding-id="issue-3" />
</Pill>
- </DocumentationTooltip>
+ </DocHelpTooltip>
);
}
*/
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';
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';
<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={[
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
</HighlightLabel>
<InputField
id="generate-token-input"
<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={[
]}
>
<HelperHintIcon />
- </DocumentationTooltip>
+ </DocHelpTooltip>
</HighlightLabel>
<InputField
id="existing-token-input"
--- /dev/null
+/*
+ * 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>
+ );
+}
--- /dev/null
+/*
+ * 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>
+ );
+}
--- /dev/null
+/*
+ * 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>
+ </>,
+ );
+}