previewCode: byText('numpy', { exact: false }),
previewIssueUnderline: byTestId('hljs-sonar-underline'),
previewIssueIndicator: byRole('button', {
- name: 'source_viewer.issues_on_line.multiple_issues_same_category.true.1.issue.clean_code_attribute_category.responsible',
+ name: 'source_viewer.issues_on_line.multiple_issues_same_category.true.1.issue.type.code_smell.issue.clean_code_attribute_category.responsible',
}),
issuesViewPage: byText('/project/issues?open=some-issue&id=foo'),
previewMarkdown: byText('Learning a cosine with keras'),
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { Spinner } from '@sonarsource/echoes-react';
-import {
- Card,
- FlagMessage,
- HelperHintIcon,
- KeyboardHint,
- LargeCenteredLayout,
- LightLabel,
-} from 'design-system';
+import { IconQuestionMark, Spinner, Text } from '@sonarsource/echoes-react';
+import { Card, FlagMessage, KeyboardHint, LargeCenteredLayout } from 'design-system';
import { difference, intersection } from 'lodash';
import * as React from 'react';
import { Helmet } from 'react-helmet-async';
return (
<LargeCenteredLayout className="sw-py-8 sw-typo-lg" id="code-page">
<Helmet defer={false} title={sourceViewer !== undefined ? sourceViewer.name : defaultTitle} />
-
<A11ySkipTarget anchor="code_main" />
-
{!canBrowseAllChildProjects && isPortfolio && (
<FlagMessage variant="warning" className="it__portfolio_warning sw-mb-4">
{translate('code_viewer.not_all_measures_are_shown')}
className="sw-ml-2"
overlay={translate('code_viewer.not_all_measures_are_shown.help')}
>
- <HelperHintIcon />
+ <IconQuestionMark />
</HelpTooltip>
</FlagMessage>
)}
{!hasComponents && sourceViewer === undefined && (
<div className="sw-flex sw-align-center sw-flex-col sw-fixed sw-top-1/2">
- <LightLabel>
+ <Text isSubdued>
{translate(
'code_viewer.no_source_code_displayed_due_to_empty_analysis',
component.qualifier,
)}
- </LightLabel>
+ </Text>
</div>
)}
areCCTMeasuresComputed as areCCTMeasuresComputedFn,
isDiffMetric,
} from '../../../helpers/measures';
+import { useIsLegacyCCTMode } from '../../../queries/settings';
import { BranchLike } from '../../../types/branch-like';
import { isApplication, isProject } from '../../../types/component';
import { Metric, ComponentMeasure as TypeComponentMeasure } from '../../../types/types';
export default function ComponentMeasure(props: Props) {
const { component, metric, branchLike } = props;
const isProjectLike = isProject(component.qualifier) || isApplication(component.qualifier);
+ const { data: isLegacy } = useIsLegacyCCTMode();
const isReleasability = metric.key === MetricKey.releasability_rating;
let finalMetricKey = isProjectLike && isReleasability ? MetricKey.alert_status : metric.key;
const finalMetricType = isProjectLike && isReleasability ? MetricType.Level : metric.type;
- const areCCTMeasasuresComputed = areCCTMeasuresComputedFn(component.measures);
- finalMetricKey = areCCTMeasasuresComputed
+ const areCCTMeasuresComputed = !isLegacy && areCCTMeasuresComputedFn(component.measures);
+ finalMetricKey = areCCTMeasuresComputed
? (OLD_TO_NEW_TAXONOMY_METRICS_MAP[finalMetricKey as MetricKey] ?? finalMetricKey)
: finalMetricKey;
OLD_TO_NEW_TAXONOMY_METRICS_MAP,
} from '../../../helpers/constants';
import { translate } from '../../../helpers/l10n';
+import { useIsLegacyCCTMode } from '../../../queries/settings';
import { ComponentMeasure } from '../../../types/types';
interface ComponentsHeaderProps {
export default function ComponentsHeader(props: ComponentsHeaderProps) {
const { baseComponent, canBePinned = true, metrics, rootComponent, showAnalysisDate } = props;
+ const { data: isLegacy = false } = useIsLegacyCCTMode();
const isPortfolio = isPortfolioLike(rootComponent.qualifier);
let columns: string[] = [];
let Cell: typeof NumericalCell;
Cell = RatingCell;
} else {
columns = metrics.map((m: MetricKey) => {
- const metric = OLD_TO_NEW_TAXONOMY_METRICS_MAP[m] ?? m;
+ const metric = isLegacy ? m : (OLD_TO_NEW_TAXONOMY_METRICS_MAP[m] ?? m);
return translate(
'metric',
// Check one of the domains.
await user.click(ui.maintainabilityDomainBtn.get());
[
- 'component_measures.metric.new_code_smells.name 9',
+ 'component_measures.leak_awaiting_analysis.name 9',
'Added Technical Debt work_duration.x_minutes.1',
'Technical Debt Ratio on New Code 1.0%',
'Maintainability Rating on New Code metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%',
- 'component_measures.metric.code_smells.name 9',
+ 'component_measures.awaiting_analysis.name 9',
'Technical Debt work_duration.x_minutes.1',
'Technical Debt Ratio 1.0%',
'Maintainability Rating metric.has_rating_X.E metric.sqale_rating.tooltip.E.0.0%',
const { ui } = getPageObject();
renderMeasuresApp('component_measures/metric/bugs?id=foo');
await ui.appLoaded();
- expect(ui.measureLink('component_measures.metric.bugs.name 0').get()).toHaveAttribute(
+ expect(ui.measureLink('component_measures.awaiting_analysis.name 0').get()).toHaveAttribute(
'aria-current',
'true',
);
hasMessage,
translate,
} from '../../../helpers/l10n';
+import { useIsLegacyCCTMode } from '../../../queries/settings';
import { MeasureEnhanced } from '../../../types/types';
import { useBubbleChartMetrics } from '../hooks';
import {
export default function DomainSubnavigation(props: Readonly<Props>) {
const { componentKey, domain, onChange, open, selected, showFullMeasures, measures } = props;
+ const { data: isLegacy = false } = useIsLegacyCCTMode();
const helperMessageKey = `component_measures.domain_subnavigation.${domain.name}.help`;
const helper = hasMessage(helperMessageKey) ? translate(helperMessageKey) : undefined;
const items = addMeasureCategories(domain.name, domain.measures);
key={item.metric.key}
componentKey={componentKey}
measure={item}
- name={getMetricSubnavigationName(item.metric, translateMetric)}
+ name={getMetricSubnavigationName(item.metric, translateMetric, false, isLegacy)}
onChange={onChange}
selected={selected}
/>
metric: Metric,
translateFn: (metric: Metric) => string,
isDiff = false,
+ isLegacy = false,
) {
+ // MQR mode and old taxonomy metrics, we return "Issues" for them anyway
+ if (!isLegacy && OLD_TAXONOMY_METRICS.includes(metric.key as MetricKey)) {
+ return translate('component_measures.awaiting_analysis.name');
+ }
+ if (!isLegacy && LEAK_OLD_TAXONOMY_METRICS.includes(metric.key as MetricKey)) {
+ return translate('component_measures.leak_awaiting_analysis.name');
+ }
+
if (
[
...LEAK_CCT_SOFTWARE_QUALITY_METRICS,
import { getBaseUrl } from '../../helpers/system';
import { isDefined } from '../../helpers/types';
import { getBranchLikeUrl, getCodeUrl } from '../../helpers/urls';
+import { useIsLegacyCCTMode } from '../../queries/settings';
import type { BranchLike } from '../../types/branch-like';
import { IssueType } from '../../types/issues';
import type { Measure, SourceViewerFile } from '../../types/types';
export default function SourceViewerHeader(props: Readonly<Props>) {
const intl = useIntl();
+ const { data: isLegacy = false } = useIsLegacyCCTMode();
const { showMeasures, branchLike, hidePinOption, openComponent, componentMeasures } = props;
const { key, measures, path, project, projectName, q } = props.sourceViewerFile;
const rawSourcesLink = `${getBaseUrl()}/api/sources/raw?${query}`;
const renderIssueMeasures = () => {
- const areCCTMeasuresComputed = areCCTMeasuresComputedFn(componentMeasures);
+ const areCCTMeasuresComputed = !isLegacy && areCCTMeasuresComputedFn(componentMeasures);
return (
componentMeasures &&
: { types: getIssueTypeBySoftwareQuality(quality) }),
});
- const qualityTitle = intl.formatMessage({ id: `metric.${metric}.short_name` });
+ const qualityTitle = intl.formatMessage({
+ id: `metric.${isLegacy ? deprecatedMetric : metric}.short_name`,
+ });
return (
<div className="sw-flex sw-flex-col sw-gap-1" key={quality}>
import { HttpStatus } from '../../../helpers/request';
import { mockIssue, mockLoggedInUser, mockMeasure } from '../../../helpers/testMocks';
import { renderComponent } from '../../../helpers/testReactTestingUtils';
+import { SettingsKey } from '../../../types/settings';
import { RestUserDetailed } from '../../../types/users';
import SourceViewer, { Props } from '../SourceViewer';
import loadIssues from '../helpers/loadIssues';
expect(within(row).queryByRole('button')).not.toBeInTheDocument();
});
-it('should show issue indicator', async () => {
+it.each([
+ ['MQR mode', 'true', ''],
+ ['Legacy mode', 'false', '.legacy'],
+])('should show issue indicator in %s', async (_, mode, translationKey) => {
+ settingsHandler.set(SettingsKey.MQRMode, mode);
jest.mocked(loadIssues).mockResolvedValueOnce([
mockIssue(false, {
key: 'first-issue',
const issueRow = within(row);
expect(issueRow.getByText('2')).toBeInTheDocument();
- await user.click(
- issueRow.getByRole('button', {
- name: 'source_viewer.issues_on_line.multiple_issues_same_category.true.2.issue.clean_code_attribute_category.responsible',
- }),
- );
+ const issueIndicator = await issueRow.findByRole('button', {
+ name: `source_viewer.issues_on_line.multiple_issues_same_category${translationKey}.true.2.issue.type.bug.plural.issue.clean_code_attribute_category.responsible`,
+ });
+ await user.click(issueIndicator);
+
+ expect(await screen.findByRole('tooltip')).toBeInTheDocument();
});
it('should show coverage information', async () => {
import * as React from 'react';
import { useIntl } from 'react-intl';
import Tooltip from '../../../components/controls/Tooltip';
+import { useIsLegacyCCTMode } from '../../../queries/settings';
import { Issue, SourceLine } from '../../../types/types';
const MOUSE_LEAVE_DELAY = 0.25;
const { issues, issuesOpen, line, as = 'td' } = props;
const hasIssues = issues.length > 0;
const intl = useIntl();
+ const { data: isLegacy } = useIsLegacyCCTMode();
if (!hasIssues) {
return <LineMeta />;
}
const issueAttributeCategories = uniq(issues.map((issue) => issue.cleanCodeAttributeCategory));
+ const issueTypes = uniq(issues.map((issue) => issue.type));
let tooltipContent;
- if (issueAttributeCategories.length > 1) {
+ if (isLegacy ? issueTypes.length > 1 : issueAttributeCategories.length > 1) {
tooltipContent = intl.formatMessage(
{ id: 'source_viewer.issues_on_line.multiple_issues' },
{ show: !issuesOpen },
);
} else {
tooltipContent = intl.formatMessage(
- { id: 'source_viewer.issues_on_line.multiple_issues_same_category' },
+ {
+ id: `source_viewer.issues_on_line.multiple_issues_same_category${isLegacy ? '.legacy' : ''}`,
+ },
{
show: !issuesOpen,
count: issues.length,
+ issueType: intl
+ .formatMessage({
+ id: `issue.type.${issueTypes[0]}${issues.length > 1 ? '.plural' : ''}`,
+ })
+ .toLowerCase(),
category: intl
.formatMessage({
id: `issue.clean_code_attribute_category.${issueAttributeCategories[0]}`,
return Stream.of(
Arguments.of(true, true),
Arguments.of(false, false),
- Arguments.of(null, false)
+ Arguments.of(null, true)
);
}
metric.branch_coverage.name=Condition Coverage
metric.bugs.description=Bugs
metric.bugs.name=Bugs
+metric.bugs.short_name=Bugs
metric.ca.description=Afferent couplings
metric.ca.name=Afferent Couplings
metric.ce.description=Efferent couplings
metric.class_complexity_distribution.name=Class Distribution / Complexity
metric.code_smells.description=Code Smells
metric.code_smells.name=Code Smells
+metric.code_smells.short_name=Code Smells
metric.cognitive_complexity.description=Cognitive complexity
metric.cognitive_complexity.name=Cognitive Complexity
metric.commented_out_code_lines.description=Commented lines of code
metric.violations.short_name=Issues
metric.vulnerabilities.description=Vulnerabilities
metric.vulnerabilities.name=Vulnerabilities
+metric.vulnerabilities.short_name=Vulnerabilities
metric.wont_fix_issues.description=Won't fix issues
metric.wont_fix_issues.name=Won't Fix Issues
metric.accepted_issues.description=Accepted issues
source_viewer.issues_on_line.multiple_issues={show, select, true {Show} other {Hide}} multiple issues on this line
source_viewer.issues_on_line.multiple_issues_same_category={show, select, true {Show} other {Hide}} {count} {category} {count, plural, one {issue} other {issues}} on this line
+source_viewer.issues_on_line.multiple_issues_same_category.legacy={show, select, true {Show} other {Hide}} {count} {issueType} on this line
source_viewer.load_more_code=Load More Code
source_viewer.loading_more_code=Loading More Code...
component_measures.skip_to_navigation=Skip to measure navigation
component_measures.see_metric_history=See history
component_measures.leak_legend.new_code=New Code:
+component_measures.awaiting_analysis.name=Issues
+component_measures.leak_awaiting_analysis.name=Issues
component_measures.overview.project_overview.subnavigation=Project Overview
component_measures.overview.project_overview.title=Risk
component_measures.metric.new_security_issues.name=Issues
component_measures.metric.new_security_issues.detailed_name=New Issues
-component_measures.metric.new_vulnerabilities.name=Issues
-component_measures.metric.new_vulnerabilities.detailed_name=New Issues
+component_measures.metric.new_vulnerabilities.name=Vulnerabilities
+component_measures.metric.new_vulnerabilities.detailed_name=New Vulnerabilities
component_measures.metric.new_reliability_issues.name=Issues
component_measures.metric.new_reliability_issues.detailed_name=New Issues
component_measures.metric.new_maintainability_issues.name=Issues
component_measures.metric.new_maintainability_issues.detailed_name=New Issues
-component_measures.metric.new_code_smells.name=Issues
-component_measures.metric.new_code_smells.detailed_name=New Issues
+component_measures.metric.new_code_smells.name=Code Smells
+component_measures.metric.new_code_smells.detailed_name=New Code Smells
component_measures.metric.new_violations.name=Open Issues
component_measures.metric.new_violations.detailed_name=New Open Issues
component_measures.metric.new_accepted_issues.name=Accepted Issues
component_measures.metric.new_accepted_issues.detailed_name=New Accepted Issues
-component_measures.metric.new_bugs.name=Issues
-component_measures.metric.new_bugs.detailed_name=New Issues
+component_measures.metric.new_bugs.name=Bugs
+component_measures.metric.new_bugs.detailed_name=New Bugs
component_measures.metric.security_issues.name=Issues
-component_measures.metric.vulnerabilities.name=Issues
+component_measures.metric.vulnerabilities.name=Vulnerabilities
component_measures.metric.reliability_issues.name=Issues
-component_measures.metric.bugs.name=Issues
+component_measures.metric.bugs.name=Bugs
component_measures.metric.maintainability_issues.name=Issues
-component_measures.metric.code_smells.name=Issues
+component_measures.metric.code_smells.name=Code Smells
component_measures.metric.violations.name=Open Issues
component_measures.metric.accepted_issues.name=Accepted Issues
component_measures.metric.confirmed_issues.name=Confirmed Issues
component_measures.metric.false_positive_issues.name=False Positive Issues
-
#------------------------------------------------------------------------------
#
# DOCS