From 2fa10f62f1534816e70098a6b63647ef8d13424c Mon Sep 17 00:00:00 2001 From: Ismail Cherri Date: Mon, 28 Oct 2024 13:23:53 +0100 Subject: [PATCH] SONAR-23196 Filter graph custom metrics based on current MQR mode --- .../__tests__/ProjectActivityApp-it.tsx | 10 +- .../js/apps/quality-gates/components/List.tsx | 2 +- .../activity-graph/AddGraphMetric.tsx | 38 ++++- .../activity-graph/AddGraphMetricPopup.tsx | 47 +----- .../activity-graph/GraphsHeader.tsx | 4 + .../activity-graph/GraphsLegendItem.tsx | 39 ++--- .../__tests__/ActivityGraph-it.tsx | 146 ++++++++++-------- .../src/main/js/helpers/constants.ts | 6 +- .../resources/org/sonar/l10n/core.properties | 39 ++++- 9 files changed, 176 insertions(+), 155 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx index c44155f4a92..63deee154e3 100644 --- a/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx +++ b/server/sonar-web/src/main/js/apps/projectActivity/components/__tests__/ProjectActivityApp-it.tsx @@ -521,7 +521,11 @@ describe('graph interactions', () => { expect(ui.issuesPopupCell.get()).toBeInTheDocument(); }); - it('should correctly handle customizing the graph', async () => { + it.each([ + ['MQR', 'true', MetricKey.maintainability_issues], + ['Standard', 'false', MetricKey.code_smells], + ])('should correctly handle customizing the graph in %s mode', async (_, mode, metric) => { + settingsHandler.set(SettingsKey.MQRMode, mode); const { ui } = getPageObject(); renderProjectActivityAppContainer(); await ui.appLoaded(); @@ -532,7 +536,7 @@ describe('graph interactions', () => { // Add metrics. await ui.openMetricsDropdown(); - await ui.toggleMetric(MetricKey.bugs); + await ui.toggleMetric(metric); await ui.toggleMetric(MetricKey.security_hotspots_reviewed); await ui.closeMetricsDropdown(); @@ -540,7 +544,7 @@ describe('graph interactions', () => { // Remove metrics. await ui.openMetricsDropdown(); - await ui.toggleMetric(MetricKey.bugs); + await ui.toggleMetric(metric); await ui.toggleMetric(MetricKey.security_hotspots_reviewed); await ui.closeMetricsDropdown(); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx index e5707e03241..a2c29c20ff8 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx @@ -103,7 +103,7 @@ export default function List({ qualityGates, currentQualityGate }: Readonly diff --git a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx index 6e9b3447c57..1b4ef643205 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetric.tsx @@ -25,7 +25,13 @@ import { Dropdown } from '~design-system'; import { MetricKey, MetricType } from '~sonar-aligned/types/metrics'; import { CCT_SOFTWARE_QUALITY_METRICS, + DEPRECATED_ACTIVITY_METRICS, HIDDEN_METRICS, + LEAK_CCT_SOFTWARE_QUALITY_METRICS, + LEAK_OLD_TAXONOMY_METRICS, + LEAK_OLD_TAXONOMY_RATINGS, + OLD_TAXONOMY_METRICS, + SOFTWARE_QUALITY_RATING_METRICS, SOFTWARE_QUALITY_RATING_METRICS_MAP, } from '../../helpers/constants'; import { getLocalizedMetricName, translate } from '../../helpers/l10n'; @@ -34,6 +40,7 @@ import { Metric } from '../../types/types'; import AddGraphMetricPopup from './AddGraphMetricPopup'; interface Props { + isStandardMode?: boolean; metrics: Metric[]; metricsTypeFilter?: string[]; onAddMetric: (metric: string) => void; @@ -60,10 +67,8 @@ export default class AddGraphMetric extends React.PureComponent { ); }; - filterMetricsElements = ( - { metricsTypeFilter, metrics, selectedMetrics }: Props, - query: string, - ) => { + filterMetricsElements = (query: string) => { + const { metrics, selectedMetrics, metricsTypeFilter, isStandardMode } = this.props; return metrics .filter((metric) => { if (metric.hidden) { @@ -81,6 +86,27 @@ export default class AddGraphMetric extends React.PureComponent { if (HIDDEN_METRICS.includes(metric.key as MetricKey)) { return false; } + if ( + isStandardMode && + [ + ...LEAK_CCT_SOFTWARE_QUALITY_METRICS, + ...CCT_SOFTWARE_QUALITY_METRICS, + ...SOFTWARE_QUALITY_RATING_METRICS, + ].includes(metric.key as MetricKey) + ) { + return false; + } + if ( + !isStandardMode && + [ + ...LEAK_OLD_TAXONOMY_METRICS, + ...OLD_TAXONOMY_METRICS, + ...LEAK_OLD_TAXONOMY_RATINGS, + ...DEPRECATED_ACTIVITY_METRICS, + ].includes(metric.key as MetricKey) + ) { + return false; + } if (Object.values(SOFTWARE_QUALITY_RATING_METRICS_MAP).includes(metric.key as MetricKey)) { return false; } @@ -123,7 +149,7 @@ export default class AddGraphMetric extends React.PureComponent { this.setState((state) => { return { selectedMetrics: sortBy([...state.selectedMetrics, metric]), - metrics: this.filterMetricsElements(this.props, state.query), + metrics: this.filterMetricsElements(state.query), }; }); }; @@ -140,7 +166,7 @@ export default class AddGraphMetric extends React.PureComponent { render() { const { query } = this.state; - const filteredMetrics = this.filterMetricsElements(this.props, query); + const filteredMetrics = this.filterMetricsElements(query); const selectedMetrics = this.getSelectedMetricsElements( this.props.metrics, this.props.selectedMetrics, diff --git a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx index 54f5c21705c..07d00062654 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/AddGraphMetricPopup.tsx @@ -18,13 +18,10 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import * as React from 'react'; -import { FormattedMessage, useIntl } from 'react-intl'; -import { Badge, FlagMessage, MultiSelectMenu } from '~design-system'; +import { ReactNode, useCallback } from 'react'; +import { FlagMessage, MultiSelectMenu } from '~design-system'; import { MetricKey } from '~sonar-aligned/types/metrics'; -import { DEPRECATED_ACTIVITY_METRICS } from '../../helpers/constants'; import { getLocalizedMetricName, translate, translateWithParameters } from '../../helpers/l10n'; -import { getDeprecatedTranslationKeyForTooltip } from './utils'; export interface AddGraphMetricPopupProps { elements: string[]; @@ -42,8 +39,7 @@ export default function AddGraphMetricPopup({ metricsTypeFilter, ...props }: Readonly) { - const intl = useIntl(); - let footerNode: React.ReactNode = ''; + let footerNode: ReactNode = ''; if (props.selectedElements.length >= 6) { footerNode = ( @@ -65,37 +61,9 @@ export default function AddGraphMetricPopup({ ); } - const renderAriaLabel = (key: MetricKey) => { - const metricName = getLocalizedMetricName({ key }); - const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key); - - return isDeprecated - ? `${metricName} (${intl.formatMessage({ id: 'deprecated' })})` - : metricName; - }; - - const renderLabel = (key: MetricKey) => { - const metricName = getLocalizedMetricName({ key }); - const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key); - - return ( - <> - {metricName} - {isDeprecated && ( - {intl.formatMessage({ id: 'deprecated' })} - )} - - ); - }; - - const renderTooltip = (key: MetricKey) => { - const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(key); - if (isDeprecated) { - return ; - } - - return null; - }; + const renderLabel = useCallback((key: MetricKey) => { + return getLocalizedMetricName({ key }); + }, []); return ( elements.includes(item) && props.onSelect(item)} onUnselect={props.onUnselect} placeholder={translate('search.search_for_metrics')} - renderAriaLabel={renderAriaLabel} + renderAriaLabel={renderLabel} renderLabel={renderLabel} - renderTooltip={renderTooltip} selectedElements={props.selectedElements} listSize={0} /> diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx index 35d1150b9cd..88785de65ce 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsHeader.tsx @@ -21,6 +21,7 @@ import { ButtonGroup, InputSize, Select } from '@sonarsource/echoes-react'; import * as React from 'react'; import { translate } from '../../helpers/l10n'; +import { useStandardExperienceMode } from '../../queries/settings'; import { GraphType } from '../../types/project-activity'; import { Metric } from '../../types/types'; import AddGraphMetric from './AddGraphMetric'; @@ -47,6 +48,8 @@ export default function GraphsHeader(props: Readonly) { selectedMetrics = [], } = props; + const { data: isStandardMode } = useStandardExperienceMode(); + const handleGraphChange = React.useCallback( (value: GraphType) => { if (value !== graph) { @@ -87,6 +90,7 @@ export default function GraphsHeader(props: Readonly) { metricsTypeFilter={metricsTypeFilter} onRemoveMetric={props.onRemoveCustomMetric} selectedMetrics={selectedMetrics} + isStandardMode={isStandardMode} /> )} diff --git a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx index 90e841ffd21..dbd3729e914 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/GraphsLegendItem.tsx @@ -19,15 +19,11 @@ */ import styled from '@emotion/styled'; +import { ButtonIcon, ButtonSize, IconWarning, IconX } from '@sonarsource/echoes-react'; import classNames from 'classnames'; -import { FormattedMessage, useIntl } from 'react-intl'; -import { Badge, CloseIcon, FlagWarningIcon, InteractiveIcon, themeBorder } from '~design-system'; -import { MetricKey } from '~sonar-aligned/types/metrics'; -import { DEPRECATED_ACTIVITY_METRICS } from '../../helpers/constants'; +import { themeBorder } from '~design-system'; import { translateWithParameters } from '../../helpers/l10n'; -import Tooltip from '../controls/Tooltip'; import { ChartLegend } from './ChartLegend'; -import { getDeprecatedTranslationKeyForTooltip } from './utils'; interface Props { className?: string; @@ -45,11 +41,8 @@ export function GraphsLegendItem({ name, removeMetric, showWarning, -}: Props) { - const intl = useIntl(); - +}: Readonly) { const isActionable = removeMetric !== undefined; - const isDeprecated = DEPRECATED_ACTIVITY_METRICS.includes(metric as MetricKey); return ( {showWarning ? ( - + ) : ( )} {name} - {isDeprecated && ( - - } - > -
- {intl.formatMessage({ id: 'deprecated' })} -
-
- )} {isActionable && ( - removeMetric(metric)} /> )} diff --git a/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx b/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx index 634b4ac1845..e144fcf2929 100644 --- a/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx +++ b/server/sonar-web/src/main/js/components/activity-graph/__tests__/ActivityGraph-it.tsx @@ -29,16 +29,15 @@ import { byText, } from '~sonar-aligned/helpers/testSelector'; import { MetricKey, MetricType } from '~sonar-aligned/types/metrics'; -import { - CCT_SOFTWARE_QUALITY_METRICS, - DEPRECATED_ACTIVITY_METRICS, -} from '../../../helpers/constants'; +import { settingsHandler } from '../../../apps/issues/test-utils'; +import { CCT_SOFTWARE_QUALITY_METRICS } from '../../../helpers/constants'; import { parseDate } from '../../../helpers/dates'; import { mockHistoryItem, mockMeasureHistory } from '../../../helpers/mocks/project-activity'; import { mockMetric } from '../../../helpers/testMocks'; import { renderComponent } from '../../../helpers/testReactTestingUtils'; import { ComponentPropsType } from '../../../helpers/testUtils'; import { GraphType, MeasureHistory } from '../../../types/project-activity'; +import { SettingsKey } from '../../../types/settings'; import { Metric } from '../../../types/types'; import GraphsHeader from '../GraphsHeader'; import GraphsHistory from '../GraphsHistory'; @@ -55,7 +54,11 @@ describe('rendering', () => { expect(await screen.findByText('loading')).toBeInTheDocument(); }); - it('should show the correct legend items', async () => { + it.each([ + ['MQR', 'true', MetricKey.maintainability_issues], + ['Standard', 'false', MetricKey.code_smells], + ])('should show the correct legend items in %s mode', async (_, mode, metric) => { + settingsHandler.set(SettingsKey.MQRMode, mode); const { ui, user } = getPageObject(); renderActivityGraph(); @@ -66,12 +69,12 @@ describe('rendering', () => { // Switch to custom graph. await ui.changeGraphType(GraphType.custom); await ui.openAddMetrics(); - await ui.clickOnMetric(MetricKey.bugs); + await ui.clickOnMetric(metric); await ui.clickOnMetric(MetricKey.test_failures); await user.keyboard('{Escape}'); // These legend items are interactive (interaction tested below). - expect(ui.legendRemoveMetricBtn(MetricKey.bugs).get()).toBeInTheDocument(); + expect(ui.legendRemoveMetricBtn(metric).get()).toBeInTheDocument(); expect(ui.legendRemoveMetricBtn(MetricKey.test_failures).get()).toBeInTheDocument(); // Shows warning for metrics with no data. @@ -118,70 +121,80 @@ describe('data table modal', () => { }); }); -it('should correctly handle adding/removing custom metrics', async () => { - const { ui } = getPageObject(); - renderActivityGraph(); - - // Change graph type to "Custom". - await ui.changeGraphType(GraphType.custom); +it.each([ + [ + 'MQR', + 'true', + MetricKey.reliability_issues, + MetricKey.maintainability_issues, + MetricKey.security_issues, + ], + ['Standard', 'false', MetricKey.bugs, MetricKey.code_smells, MetricKey.vulnerabilities], +])( + 'should correctly handle adding/removing custom metrics in $s mode', + async (_, mode, bugs, codeSmells, vulnerabilities) => { + settingsHandler.set(SettingsKey.MQRMode, mode); + const { ui } = getPageObject(); + renderActivityGraph(); - // Open the "Add metrics" dropdown button; select some metrics. - await ui.openAddMetrics(); + // Change graph type to "Custom". + await ui.changeGraphType(GraphType.custom); - // We should not see DATA type or New Code metrics. - expect(ui.newBugsCheckbox.query()).not.toBeInTheDocument(); - expect(ui.burnedBudgetCheckbox.query()).not.toBeInTheDocument(); + // Open the "Add metrics" dropdown button; select some metrics. + await ui.openAddMetrics(); - // Select 3 Int types. - await ui.clickOnMetric(MetricKey.bugs); - await ui.clickOnMetric(MetricKey.code_smells); - await ui.clickOnMetric(MetricKey.confirmed_issues); - // Select 1 Percent type. - await ui.clickOnMetric(MetricKey.coverage); + // We should not see DATA type or New Code metrics. + expect(ui.metricCheckbox(`new_${bugs}`).query()).not.toBeInTheDocument(); + expect(ui.burnedBudgetCheckbox.query()).not.toBeInTheDocument(); - // We should see 2 graphs, correctly labelled. - expect(ui.graphs.getAll()).toHaveLength(2); + // Select 3 Int types. + await ui.clickOnMetric(bugs); + await ui.clickOnMetric(codeSmells); + await ui.clickOnMetric(MetricKey.accepted_issues); + // Select 1 Percent type. + await ui.clickOnMetric(MetricKey.coverage); - // old types and confirmed metrics should be deprecated and show a badge (both in dropdown and in legend) - expect(ui.deprecatedBadge.getAll()).toHaveLength(6); + // We should see 2 graphs, correctly labelled. + expect(ui.graphs.getAll()).toHaveLength(2); - // We cannot select anymore Int types. It should hide options, and show an alert. - expect(ui.vulnerabilityCheckbox.query()).not.toBeInTheDocument(); - expect(ui.hiddenOptionsAlert.get()).toBeInTheDocument(); + // We cannot select anymore Int types. It should hide options, and show an alert. + expect(ui.metricCheckbox(vulnerabilities).query()).not.toBeInTheDocument(); + expect(ui.hiddenOptionsAlert.get()).toBeInTheDocument(); - // Select 2 more Percent types. - await ui.clickOnMetric(MetricKey.duplicated_lines_density); - await ui.clickOnMetric(MetricKey.test_success_density); + // Select 2 more Percent types. + await ui.clickOnMetric(MetricKey.duplicated_lines_density); + await ui.clickOnMetric(MetricKey.test_success_density); - // We cannot select anymore options. It should disable all remaining options, and - // show a different alert. - expect(ui.maxOptionsAlert.get()).toBeInTheDocument(); - expect(ui.vulnerabilityCheckbox.get()).toBeDisabled(); + // We cannot select anymore options. It should disable all remaining options, and + // show a different alert. + expect(ui.maxOptionsAlert.get()).toBeInTheDocument(); + expect(ui.metricCheckbox(vulnerabilities).get()).toBeDisabled(); - // Disable a few options. - await ui.clickOnMetric(MetricKey.bugs); - await ui.clickOnMetric(MetricKey.code_smells); - await ui.clickOnMetric(MetricKey.coverage); + // Disable a few options. + await ui.clickOnMetric(bugs); + await ui.clickOnMetric(codeSmells); + await ui.clickOnMetric(MetricKey.coverage); - // Search for option and select it - await ui.searchForMetric('maintainability'); - expect(ui.vulnerabilityCheckbox.query()).not.toBeInTheDocument(); - await ui.clickOnMetric(MetricKey.maintainability_issues); + // Search for option and select it + await ui.searchForMetric('condition'); + expect(ui.metricCheckbox(MetricKey.branch_coverage).query()).not.toBeInTheDocument(); + await ui.clickOnMetric(MetricKey.conditions_to_cover); - // Disable percentage metrics by clicking on the legend items. - await ui.removeMetric(MetricKey.duplicated_lines_density); - await ui.removeMetric(MetricKey.test_success_density); + // Disable percentage metrics by clicking on the legend items. + await ui.removeMetric(MetricKey.duplicated_lines_density); + await ui.removeMetric(MetricKey.test_success_density); - // We should see 1 graph - expect(ui.graphs.getAll()).toHaveLength(1); + // We should see 1 graph + expect(ui.graphs.getAll()).toHaveLength(1); - // Disable final number metrics - await ui.removeMetric(MetricKey.confirmed_issues); - await ui.removeMetric(MetricKey.maintainability_issues); + // Disable final number metrics + await ui.removeMetric(MetricKey.accepted_issues); + await ui.removeMetric(MetricKey.conditions_to_cover); - // Should show message that there's no data to be rendered. - expect(ui.noDataText.get()).toBeInTheDocument(); -}); + // Should show message that there's no data to be rendered. + expect(ui.noDataText.get()).toBeInTheDocument(); + }, +); function getPageObject() { const user = userEvent.setup(); @@ -191,18 +204,15 @@ function getPageObject() { // Add/remove metrics. addMetricBtn: byRole('button', { name: 'project_activity.graphs.custom.add' }), - deprecatedBadge: byText('deprecated'), maintainabilityIssuesCheckbox: byRole('checkbox', { name: MetricKey.maintainability_issues }), newBugsCheckbox: byRole('checkbox', { name: MetricKey.new_bugs }), burnedBudgetCheckbox: byRole('checkbox', { name: MetricKey.burned_budget }), - vulnerabilityCheckbox: byRole('checkbox', { - name: `${MetricKey.vulnerabilities} (deprecated)`, - }), hiddenOptionsAlert: byText('project_activity.graphs.custom.type_x_message', { exact: false, }), maxOptionsAlert: byText('project_activity.graphs.custom.add_metric_info'), filterMetrics: byPlaceholderText('search.search_for_metrics'), + metricCheckbox: (name: string) => byRole('checkbox', { name }), legendRemoveMetricBtn: (key: string) => byRole('button', { name: `project_activity.graphs.custom.remove_metric.${key}` }), getLegendItem: (name: string) => { @@ -243,11 +253,7 @@ function getPageObject() { await user.type(ui.filterMetrics.get(), text); }, async clickOnMetric(name: MetricKey) { - await user.click( - screen.getByRole('checkbox', { - name: DEPRECATED_ACTIVITY_METRICS.includes(name) ? `${name} (deprecated)` : name, - }), - ); + await user.click(ui.metricCheckbox(name).get()); }, async removeMetric(metric: MetricKey) { await user.click(ui.legendRemoveMetricBtn(metric).get()); @@ -273,18 +279,22 @@ function renderActivityGraph( const measuresHistory: MeasureHistory[] = []; const metrics: Metric[] = []; [ + MetricKey.accepted_issues, MetricKey.violations, MetricKey.bugs, MetricKey.code_smells, - MetricKey.confirmed_issues, - MetricKey.maintainability_issues, MetricKey.vulnerabilities, + MetricKey.maintainability_issues, + MetricKey.reliability_issues, + MetricKey.security_issues, MetricKey.blocker_violations, MetricKey.lines_to_cover, MetricKey.uncovered_lines, MetricKey.coverage, MetricKey.duplicated_lines_density, MetricKey.test_success_density, + MetricKey.branch_coverage, + MetricKey.conditions_to_cover, ].forEach((metric) => { const history = times(HISTORY_COUNT - 2, (i) => { const date = parseDate(START_DATE); diff --git a/server/sonar-web/src/main/js/helpers/constants.ts b/server/sonar-web/src/main/js/helpers/constants.ts index 2145390f909..cf169fbcf94 100644 --- a/server/sonar-web/src/main/js/helpers/constants.ts +++ b/server/sonar-web/src/main/js/helpers/constants.ts @@ -200,7 +200,6 @@ export const HIDDEN_METRICS = [ ]; export const DEPRECATED_ACTIVITY_METRICS = [ - ...OLD_TAXONOMY_METRICS, MetricKey.blocker_violations, MetricKey.critical_violations, MetricKey.major_violations, @@ -268,6 +267,11 @@ export const SOFTWARE_QUALITY_RATING_METRICS = [ MetricKey.new_software_quality_reliability_remediation_effort, MetricKey.new_software_quality_security_remediation_effort, MetricKey.new_software_quality_maintainability_debt_ratio, + MetricKey.software_quality_blocker_issues, + MetricKey.software_quality_high_issues, + MetricKey.software_quality_medium_issues, + MetricKey.software_quality_low_issues, + MetricKey.software_quality_info_issues, ]; export const PROJECT_KEY_MAX_LEN = 400; diff --git a/sonar-core/src/main/resources/org/sonar/l10n/core.properties b/sonar-core/src/main/resources/org/sonar/l10n/core.properties index ab785a5a0eb..a352da7def5 100644 --- a/sonar-core/src/main/resources/org/sonar/l10n/core.properties +++ b/sonar-core/src/main/resources/org/sonar/l10n/core.properties @@ -2306,7 +2306,6 @@ quality_profiles.cannot_associate_projects_no_rules=You must activate at least 1 quality_profiles.cannot_set_default_no_rules=You must activate at least 1 rule before you can make this profile the default profile. quality_profiles.warning.used_by_projects_no_rules=The current profile is used on several projects, but it has no active rules. Please activate at least 1 rule for this profile. quality_profiles.warning.is_default_no_rules=The current profile is the default profile, but it has no active rules. Please activate at least 1 rule for this profile. -quality_profiles.x_sonarway_missing_rules={linkCount} Sonar way {count, plural, one {rule} other {rules}} not included quality_profiles.parent=Parent quality_profiles.parameter_set_to=Parameter {0} set to {1} quality_profile.summary_additional={count} additional {count, plural, one {rule} other {rules}} @@ -2555,7 +2554,7 @@ quality_gates.cayc.banner.description2=It ensures that: quality_gates.cayc_unfollow.description=You may click unlock to edit this quality gate. Adding extra conditions to a compliant quality gate can result in drawbacks. Are you reconsidering {cayc_link}? We strongly recommend this methodology to achieve a Clean Code status. quality_gates.cayc.review_update_modal.add_condition.header= {0} condition(s) on new code will be added quality_gates.cayc.review_update_modal.modify_condition.header= {0} condition(s) on new code will be modified -quality_gates.ai_generated.tootltip.message=Sonar way ensures clean AI-generated code +quality_gates.ai_generated.tooltip.message=Sonar way ensures clean AI-generated code quality_gates.ai_generated.description=Sonar way ensures {link} quality_gates.ai_generated.description.clean_ai_generated_code=clean AI-generated code quality_gates.mqr_mode_update.tooltip.message=Update the metrics of this quality gate @@ -2911,7 +2910,6 @@ email_notification.form.save_configuration=Save configuration email_notification.form.save_configuration.create_success=Email configuration saved successfully. email_notification.form.save_configuration.update_success=Email configuration updated successfully. email_notification.form.delete_configuration=Delete configuration -email_notification.state.value_should_be_valid_email=A valid email address is required. email_notification.overview.heading=SMTP configuration settings email_notification.overview.authentication_type=Authentication type email_notification.overview.private=Hidden for security reasons @@ -3722,6 +3720,38 @@ metric.new_reliability_issues.short_name=New Reliability metric.new_security_issues.name=New Security Issues metric.new_security_issues.description=New security issues metric.new_security_issues.short_name=New Security +metric.software_quality_blocker_issues.description=Blocker issues +metric.software_quality_blocker_issues.name=Blocker Issues +metric.software_quality_high_issues.description=Critical issues +metric.software_quality_high_issues.name=Critical Issues +metric.software_quality_info_issues.description=Info issues +metric.software_quality_info_issues.name=Info Issues +metric.software_quality_medium_issues.description=Major issues +metric.software_quality_medium_issues.name=Major Issues +metric.software_quality_low_issues.description=Minor issues +metric.software_quality_low_issues.name=Minor Issues +metric.new_software_quality_blocker_issues.description=New Blocker issues +metric.new_software_quality_blocker_issues.name=New Blocker Issues +metric.new_software_quality_high_issues.description=New Critical issues +metric.new_software_quality_high_issues.name=New Critical Issues +metric.new_software_quality_info_issues.description=New Info issues +metric.new_software_quality_info_issues.name=New Info Issues +metric.new_software_quality_medium_issues.description=New Major issues +metric.new_software_quality_medium_issues.name=New Major Issues +metric.new_software_quality_low_issues.description=New Minor issues +metric.new_software_quality_low_issues.name=New Minor Issues +metric.software_quality_maintainability_issues.name=Maintainability Issues +metric.software_quality_maintainability_issues.description=Maintainability issues +metric.software_quality_reliability_issues.name=Reliability Issues +metric.software_quality_reliability_issues.description=Reliability issues +metric.software_quality_security_issues.name=Security Issues +metric.software_quality_security_issues.description=Security issues +metric.new_software_quality_maintainability_issues.name=New Maintainability Issues +metric.new_software_quality_maintainability_issues.description=New maintainability issues +metric.new_software_quality_reliability_issues.name=New Reliability Issues +metric.new_software_quality_reliability_issues.description=New reliability issues +metric.new_software_quality_security_issues.name=New Security Issues +metric.new_software_quality_security_issues.description=New security issues #------------------------------------------------------------------------------ # @@ -4294,7 +4324,6 @@ overview.pull_request.fixed_issues=Fixed issues overview.pull_request.fixed_issues.help=Estimation of issues fixed by this PR overview.pull_request.fixed_issues.disclaimer=Only issues fixed on the files modified by the pull request are taken into account. Issues incidentally fixed on unmodified files are not counted. overview.pull_request.fixed_issues.disclaimer.2=When the pull request and the target branch are not synchronized, issues introduced on the target branch may be incorrectly considered fixed by the pull request. Rebasing the pull request would give an updated value. -overview.accepted_issues=Accepted issues overview.accepted_issues.help=Valid issues that were not fixed overview.quality_gate=Quality Gate overview.quality_gate_x=Quality Gate: {0} @@ -4872,7 +4901,6 @@ onboarding.create_project.gitlab.subtitle=Import projects from one of your GitLa onboarding.create_project.gitlab.subtitle.with_monorepo=Import projects from one of your GitLab groups or {monorepoSetupLink}. onboarding.create_project.gitlab.no_projects=No projects could be fetched from GitLab. Contact your system administrator, or {link}. onboarding.create_project.gitlab.link=See on GitLab -onboarding.create_project.monorepo.no_projects=No projects could be fetch from {almKey}. Contact your system administrator. onboarding.create_project.bitbucket.title=Bitbucket Server project onboarding onboarding.create_project.bitbucket.subtitle=Import projects from one of your Bitbucket server workspaces onboarding.create_project.bitbucket.subtitle.with_monorepo=Import projects from one of your Bitbucket server workspaces or {monorepoSetupLink}. @@ -4904,7 +4932,6 @@ onboarding.create_project.monorepo.warning.message_admin.link=DevOps Platform in onboarding.create_project.new_code_definition.title=Set up project for Clean as You Code onboarding.create_x_project.new_code_definition.title=Set up {count, plural, one {project} other {# projects}} for Clean as You Code -onboarding.create_project.new_code_definition.title=Set up project for Clean as You Code onboarding.create_project.new_code_definition.description=The new code definition sets which part of your code will be considered new code. This helps you focus attention on the most recent changes to your project, enabling you to follow the Clean as You Code methodology. Learn more: {link} onboarding.create_project.new_code_definition.description.link=Defining New Code onboarding.create_project.new_code_definition.create_x_projects=Create {count, plural, one {project} other {# projects}} -- 2.39.5