* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+import { Button, Spinner } from '@sonarsource/echoes-react';
import { uniqBy } from 'lodash';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
LightPrimary,
Link,
Note,
- Spinner,
SubHeading,
} from '~design-system';
import DocHelpTooltip from '~sonar-aligned/components/controls/DocHelpTooltip';
import { DocLink } from '../../../helpers/doc-links';
import { useDocUrl } from '../../../helpers/docs';
import { getLocalizedMetricName, translate } from '../../../helpers/l10n';
+import { useStandardExperienceMode } from '../../../queries/settings';
+import { MetricKey } from '../../../sonar-aligned/types/metrics';
import { Feature } from '../../../types/features';
import { CaycStatus, Condition as ConditionType, QualityGate } from '../../../types/types';
-import { groupAndSortByPriorityConditions, isQualityGateOptimized } from '../utils';
+import {
+ groupAndSortByPriorityConditions,
+ isQualityGateOptimized,
+ MQR_CONDITIONS_MAP,
+ STANDARD_CONDITIONS_MAP,
+} from '../utils';
import AddConditionModal from './AddConditionModal';
import AIGeneratedIcon from './AIGeneratedIcon';
import CaycCompliantBanner from './CaycCompliantBanner';
import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal';
import ConditionsTable from './ConditionsTable';
import QGRecommendedIcon from './QGRecommendedIcon';
+import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
interface Props {
isFetching?: boolean;
const [editing, setEditing] = React.useState<boolean>(caycStatus === CaycStatus.NonCompliant);
const metrics = useMetrics();
const { hasFeature } = useAvailableFeatures();
+ const { data: isStandardMode, isLoading } = useStandardExperienceMode();
const canEdit = Boolean(actions?.manageConditions);
const existingConditions = conditions.filter((condition) => metrics[condition.metric]);
[qualityGate, conditions, metrics, isOptimizing, canEdit],
);
+ const conditionsToOtherModeMap = isStandardMode ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+
return (
- <div>
+ <Spinner isLoading={isLoading}>
<CaYCConditionsSimplificationGuide qualityGate={qualityGate} />
-
{isBuiltIn && (
<div className="sw-flex sw-items-center">
<QGRecommendedIcon className="sw-mr-1" />
</LightLabel>
</div>
)}
-
{isAICodeAssuranceQualityGate && (
<div className="sw-flex sw-items-center sw-mt-2">
<AIGeneratedIcon className="sw-mr-1" />
</LightLabel>
</div>
)}
-
{isCompliantCustomQualityGate && !isOptimizing && <CaycCompliantBanner />}
{isCompliantCustomQualityGate && isOptimizing && canEdit && (
<CaycFixOptimizeBanner renderCaycModal={renderCaycModal} isOptimizing />
{caycStatus === CaycStatus.NonCompliant && canEdit && (
<CaycFixOptimizeBanner renderCaycModal={renderCaycModal} />
)}
-
+ <UpdateConditionsFromOtherModeModal
+ qualityGateName={qualityGate.name}
+ newCodeConditions={newCodeConditions.filter(
+ (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+ )}
+ overallCodeConditions={overallCodeConditions.filter(
+ (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+ )}
+ >
+ {/* TODO test example */}
+ <Button>Review and update metrics</Button>
+ </UpdateConditionsFromOtherModeModal>
+ <UpdateConditionsFromOtherModeModal
+ qualityGateName={qualityGate.name}
+ isSingleMetric
+ condition={newCodeConditions.find((c) => c.metric.includes('rating'))!}
+ >
+ {/* TODO test example */}
+ <Button>Test single</Button>
+ </UpdateConditionsFromOtherModeModal>
<header className="sw-flex sw-items-center sw-mt-9 sw-mb-4 sw-justify-between">
<div className="sw-flex">
<HeadingDark className="sw-typo-lg-semibold sw-m-0">
<HelperHintIcon />
</DocHelpTooltip>
)}
- <Spinner loading={isFetching} className="sw-ml-4 sw-mt-1" />
+ <Spinner isLoading={isFetching} className="sw-ml-4 sw-mt-1" />
</div>
<div>
{(caycStatus === CaycStatus.NonCompliant || editing) && canEdit && (
)}
</div>
</header>
-
{uniqDuplicates.length > 0 && (
<FlagMessage variant="warning" className="sw-flex sw-mb-4">
<div>
</div>
</FlagMessage>
)}
-
<div className="sw-flex sw-flex-col sw-gap-8">
{caycConditions.length > 0 && (
<div>
</div>
)}
</div>
-
{caycStatus !== CaycStatus.NonCompliant && !editing && canEdit && (
<div className="sw-mt-4 it__qg-unfollow-cayc">
<SubHeading as="p" className="sw-mb-2 sw-typo-default">
</ButtonSecondary>
</div>
)}
-
{existingConditions.length === 0 && (
<div className="sw-mt-4 sw-typo-default">
<LightPrimary as="p">{translate('quality_gates.no_conditions')}</LightPrimary>
</div>
)}
- </div>
+ </Spinner>
);
}
--- /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 {
+ Button,
+ ButtonVariety,
+ Heading,
+ IconArrowRight,
+ Modal,
+ ModalSize,
+ Text,
+ TextSize,
+} from '@sonarsource/echoes-react';
+import * as React from 'react';
+import { FormattedMessage, useIntl } from 'react-intl';
+import { useMetrics } from '../../../app/components/metrics/withMetricsContext';
+import DocumentationLink from '../../../components/common/DocumentationLink';
+import { ContentCell, FlagMessageV2, Table, TableRow } from '../../../design-system';
+import { DocLink } from '../../../helpers/doc-links';
+import { translate } from '../../../helpers/l10n';
+import { getOperatorLabel } from '../../../helpers/qualityGates';
+import { useUpdateOrDeleteConditionsMutation } from '../../../queries/quality-gates';
+import { useStandardExperienceMode } from '../../../queries/settings';
+import { MetricKey } from '../../../sonar-aligned/types/metrics';
+import { Condition } from '../../../types/types';
+import {
+ getLocalizedMetricNameNoDiffMetric,
+ MQR_CONDITIONS_MAP,
+ STANDARD_CONDITIONS_MAP,
+} from '../utils';
+import ConditionValue from './ConditionValue';
+
+type Props = React.PropsWithChildren & { qualityGateName: string } & (
+ | {
+ condition?: never;
+ isSingleMetric?: false;
+ newCodeConditions: Condition[];
+ overallCodeConditions: Condition[];
+ }
+ | {
+ condition: Condition;
+ isSingleMetric: true;
+ newCodeConditions?: never;
+ overallCodeConditions?: never;
+ }
+ );
+
+export default function UpdateConditionsFromOtherModeModal({
+ newCodeConditions,
+ overallCodeConditions,
+ qualityGateName,
+ isSingleMetric,
+ condition,
+ children,
+}: Readonly<Props>) {
+ const { data: isStandard } = useStandardExperienceMode();
+ const [isOpen, setOpen] = React.useState(false);
+ const [error, setError] = React.useState(false);
+ const intl = useIntl();
+ const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+ const { mutate: updateConditions, isPending } = useUpdateOrDeleteConditionsMutation(
+ qualityGateName,
+ isSingleMetric,
+ );
+
+ const onSubmit = () => {
+ const conditions = isSingleMetric
+ ? [condition]
+ : [...newCodeConditions, ...overallCodeConditions];
+
+ updateConditions(
+ conditions.map((c) => ({ ...c, metric: mapper[c.metric as MetricKey] })),
+ {
+ onSuccess: () => setOpen(false),
+ onError: () => setError(true),
+ },
+ );
+ };
+
+ return (
+ <Modal
+ isOpen={isOpen}
+ onOpenChange={setOpen}
+ title={intl.formatMessage(
+ {
+ id: `quality_gates.update_conditions.header${isSingleMetric ? '.single_metric' : ''}`,
+ },
+ { qualityGate: qualityGateName },
+ )}
+ size={isSingleMetric ? ModalSize.Default : ModalSize.Wide}
+ primaryButton={
+ <Button
+ isDisabled={isPending}
+ isLoading={isPending}
+ onClick={onSubmit}
+ id="update-metrics-button"
+ variety={ButtonVariety.Primary}
+ >
+ {intl.formatMessage({
+ id: isSingleMetric ? 'update_verb' : 'quality_gates.update_conditions.update_metrics',
+ })}
+ </Button>
+ }
+ secondaryButton={<Button onClick={() => setOpen(false)}>{translate('cancel')}</Button>}
+ content={
+ <>
+ {error && (
+ <div>
+ <FlagMessageV2 variant="error">
+ {intl.formatMessage({ id: 'quality_gates.update_conditions.error' })}
+ </FlagMessageV2>
+ </div>
+ )}
+ <Text>
+ <FormattedMessage
+ id="quality_gates.update_conditions.description.line1"
+ values={{
+ b: (chunks) => <Text isHighlighted>{chunks}</Text>,
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+ }),
+ }}
+ />
+ </Text>
+
+ {isSingleMetric && <SingleMetric condition={condition} />}
+ <Text>
+ <FormattedMessage
+ id="quality_gates.update_conditions.description.line2"
+ values={{
+ b: (chunks) => <Text isHighlighted>{chunks}</Text>,
+ }}
+ />
+ <br />
+ <br />
+ <FormattedMessage
+ id="quality_gates.update_conditions.description.line3"
+ values={{
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+ }),
+ link: (
+ <DocumentationLink to={isStandard ? DocLink.ModeStandard : DocLink.ModeMQR}>
+ {intl.formatMessage({
+ id: 'quality_gates.update_conditions.description.link',
+ })}
+ </DocumentationLink>
+ ),
+ }}
+ />
+ </Text>
+ {!isSingleMetric && (
+ <>
+ {newCodeConditions.length > 0 && (
+ <>
+ <Heading as="h3" className="sw-mt-8">
+ {intl.formatMessage({ id: 'overview.new_code' })}
+ </Heading>
+ <Table
+ columnCount={3}
+ columnWidths={['35%', '35%', 'auto']}
+ className="sw-my-2"
+ header={<Header />}
+ >
+ {newCodeConditions.map((condition) => (
+ <ConditionRow condition={condition} key={condition.id} />
+ ))}
+ </Table>
+ </>
+ )}
+ {overallCodeConditions.length > 0 && (
+ <>
+ <Heading as="h3" className="sw-mt-8">
+ {intl.formatMessage({ id: 'overview.overall_code' })}
+ </Heading>
+ <Table
+ columnCount={3}
+ columnWidths={['35%', '35%', 'auto']}
+ className="sw-my-2"
+ header={<Header />}
+ >
+ {overallCodeConditions.map((condition) => (
+ <ConditionRow condition={condition} key={condition.id} />
+ ))}
+ </Table>
+ </>
+ )}
+ </>
+ )}
+ </>
+ }
+ >
+ {React.cloneElement(children as React.ReactElement, { onClick: () => setOpen(true) })}
+ </Modal>
+ );
+}
+
+function SingleMetric({ condition }: Readonly<{ condition: Condition }>) {
+ const { data: isStandard } = useStandardExperienceMode();
+ const intl = useIntl();
+ const metrics = useMetrics();
+ const metric = metrics[condition.metric];
+ const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+ const metricFromOtherMode = mapper[metric.key as MetricKey];
+
+ return (
+ <div className="sw-flex sw-justify-between sw-my-8 sw-items-center sw-w-[80%]">
+ <div>
+ <Text as="div" size={TextSize.Small}>
+ {intl.formatMessage({
+ id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`,
+ })}
+ </Text>
+ <Text as="div" size={TextSize.Small} isHighlighted>
+ {getLocalizedMetricNameNoDiffMetric(metrics[condition.metric], metrics)}
+ </Text>
+ </div>
+ <IconArrowRight />
+ <div>
+ {metricFromOtherMode ? (
+ <>
+ <Text as="div" size={TextSize.Small}>
+ {intl.formatMessage({
+ id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`,
+ })}
+ </Text>
+ <Text as="div" size={TextSize.Small} isHighlighted>
+ {getLocalizedMetricNameNoDiffMetric(metrics[metricFromOtherMode], metrics)}
+ </Text>
+ </>
+ ) : (
+ <Text size={TextSize.Small}>
+ {intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })}
+ </Text>
+ )}
+ </div>
+ </div>
+ );
+}
+
+function Header() {
+ const intl = useIntl();
+ const { data: isStandard } = useStandardExperienceMode();
+
+ return (
+ <TableRow>
+ <ContentCell className="sw-justify-between sw-pr-4">
+ <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap">
+ {intl.formatMessage({
+ id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`,
+ })}
+ </Heading>
+ <IconArrowRight />
+ </ContentCell>
+ <ContentCell>
+ <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap">
+ {intl.formatMessage({
+ id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`,
+ })}
+ </Heading>
+ </ContentCell>
+ <ContentCell>
+ <Heading as="h4" className="sw-typo-semibold sw-m-0 sw-whitespace-nowrap">
+ {intl.formatMessage({ id: 'quality_gates.update_conditions.operator_and_value_header' })}
+ </Heading>
+ </ContentCell>
+ <ContentCell />
+ </TableRow>
+ );
+}
+
+function ConditionRow({ condition }: Readonly<{ condition: Condition }>) {
+ const { data: isStandard } = useStandardExperienceMode();
+ const intl = useIntl();
+ const metrics = useMetrics();
+ const { op = 'GT' } = condition;
+ const metric = metrics[condition.metric];
+ const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+ const metricFromOtherMode = mapper[metric?.key as MetricKey];
+
+ return (
+ <TableRow>
+ <ContentCell>{getLocalizedMetricNameNoDiffMetric(metric, metrics)}</ContentCell>
+ <ContentCell>
+ {metricFromOtherMode ? (
+ getLocalizedMetricNameNoDiffMetric(metrics[metricFromOtherMode], metrics)
+ ) : (
+ <Text colorOverride="echoes-color-text-danger">
+ {intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })}
+ </Text>
+ )}
+ </ContentCell>
+
+ <ContentCell className="sw-whitespace-nowrap">
+ {metricFromOtherMode && (
+ <Text isSubdued>
+ {getOperatorLabel(op, metric)}
+ <ConditionValue condition={condition} metric={metric} />
+ </Text>
+ )}
+ </ContentCell>
+ </TableRow>
+ );
+}
import { sortBy } from 'lodash';
import { MetricKey } from '~sonar-aligned/types/metrics';
+import { SOFTWARE_QUALITY_RATING_METRICS_MAP } from '../../helpers/constants';
import { getLocalizedMetricName } from '../../helpers/l10n';
import { isDiffMetric } from '../../helpers/measures';
import { CaycStatus, Condition, Dict, Group, Metric, QualityGate } from '../../types/types';
];
const NON_EDITABLE_CONDITIONS: MetricKey[] = [MetricKey.prioritized_rule_issues];
+export const STANDARD_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey>> = {
+ [MetricKey.new_blocker_violations]: MetricKey.new_software_quality_blocker_issues,
+ [MetricKey.new_critical_violations]: MetricKey.new_software_quality_high_issues,
+ [MetricKey.new_major_violations]: MetricKey.new_software_quality_medium_issues,
+ [MetricKey.new_minor_violations]: MetricKey.new_software_quality_low_issues,
+ [MetricKey.new_info_violations]: MetricKey.new_software_quality_info_issues,
+ [MetricKey.blocker_violations]: MetricKey.software_quality_blocker_issues,
+ [MetricKey.critical_violations]: MetricKey.software_quality_high_issues,
+ [MetricKey.major_violations]: MetricKey.software_quality_medium_issues,
+ [MetricKey.minor_violations]: MetricKey.software_quality_low_issues,
+ [MetricKey.info_violations]: MetricKey.software_quality_info_issues,
+ [MetricKey.new_vulnerabilities]: MetricKey.new_software_quality_security_issues,
+ [MetricKey.new_bugs]: MetricKey.new_software_quality_reliability_issues,
+ [MetricKey.new_code_smells]: MetricKey.new_software_quality_maintainability_issues,
+ [MetricKey.vulnerabilities]: MetricKey.software_quality_security_issues,
+ [MetricKey.bugs]: MetricKey.software_quality_reliability_issues,
+ [MetricKey.code_smells]: MetricKey.software_quality_maintainability_issues,
+ ...SOFTWARE_QUALITY_RATING_METRICS_MAP,
+};
+
+export const MQR_CONDITIONS_MAP: Partial<Record<MetricKey, MetricKey | null>> = {
+ ...Object.fromEntries(
+ Object.entries(STANDARD_CONDITIONS_MAP).map(([key, value]) => [value, key]),
+ ),
+ [MetricKey.high_impact_accepted_issues]: null,
+};
+
export function isConditionWithFixedValue(condition: Condition) {
return CAYC_CONDITIONS_WITH_FIXED_VALUE.includes(condition.metric as OptimizedCaycMetricKeys);
}
*/
import { queryOptions, useMutation, useQuery, useQueryClient } from '@tanstack/react-query';
+import { useIntl } from 'react-intl';
import { addGlobalSuccessMessage } from '~design-system';
import { BranchParameters } from '~sonar-aligned/types/branch-like';
import {
});
}
+export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric?: boolean) {
+ const queryClient = useQueryClient();
+ const intl = useIntl();
+
+ return useMutation({
+ mutationFn: (
+ conditions: (Omit<Condition, 'metric'> & { metric: string | null | undefined })[],
+ ) => {
+ const promiseArr = conditions.map((condition) =>
+ condition.metric
+ ? updateCondition(condition as Condition)
+ : deleteCondition({ id: condition.id }),
+ );
+
+ return Promise.all(promiseArr);
+ },
+ onSuccess: () => {
+ queryClient.invalidateQueries({ queryKey: qualityQuery.list() });
+ queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
+ addGlobalSuccessMessage(
+ intl.formatMessage(
+ {
+ id: isSingleMetric
+ ? 'quality_gates.condition_updated'
+ : 'quality_gates.conditions_updated_to_the_mode',
+ },
+ { qualityGateName: gateName },
+ ),
+ );
+ },
+ onError: () => {
+ queryClient.invalidateQueries({ queryKey: qualityQuery.detail(gateName) });
+ },
+ });
+}
+
export function useDeleteConditionMutation(gateName: string) {
const queryClient = useQueryClient();
accepted_issues = 'accepted_issues',
alert_status = 'alert_status',
blocker_violations = 'blocker_violations',
+ software_quality_blocker_issues = 'software_quality_blocker_issues',
branch_coverage = 'branch_coverage',
bugs = 'bugs',
+ software_quality_reliability_issues = 'software_quality_reliability_issues',
burned_budget = 'burned_budget',
business_value = 'business_value',
class_complexity = 'class_complexity',
classes = 'classes',
code_smells = 'code_smells',
+ software_quality_maintainability_issues = 'software_quality_maintainability_issues',
cognitive_complexity = 'cognitive_complexity',
comment_lines = 'comment_lines',
comment_lines_data = 'comment_lines_data',
confirmed_issues = 'confirmed_issues',
coverage = 'coverage',
critical_violations = 'critical_violations',
+ software_quality_high_issues = 'software_quality_high_issues',
development_cost = 'development_cost',
directories = 'directories',
duplicated_blocks = 'duplicated_blocks',
generated_ncloc = 'generated_ncloc',
high_impact_accepted_issues = 'high_impact_accepted_issues',
info_violations = 'info_violations',
+ software_quality_info_issues = 'software_quality_info_issues',
issues = 'issues',
last_change_on_maintainability_rating = 'last_change_on_maintainability_rating',
last_change_on_releasability_rating = 'last_change_on_releasability_rating',
maintainability_rating_effort = 'maintainability_rating_effort',
software_quality_maintainability_rating_effort = 'software_quality_maintainability_rating_effort',
major_violations = 'major_violations',
+ software_quality_medium_issues = 'software_quality_medium_issues',
minor_violations = 'minor_violations',
+ software_quality_low_issues = 'software_quality_low_issues',
ncloc = 'ncloc',
ncloc_data = 'ncloc_data',
ncloc_language_distribution = 'ncloc_language_distribution',
new_accepted_issues = 'new_accepted_issues',
new_blocker_violations = 'new_blocker_violations',
+ new_software_quality_blocker_issues = 'new_software_quality_blocker_issues',
new_branch_coverage = 'new_branch_coverage',
new_bugs = 'new_bugs',
+ new_software_quality_reliability_issues = 'new_software_quality_reliability_issues',
new_code_smells = 'new_code_smells',
+ new_software_quality_maintainability_issues = 'new_software_quality_maintainability_issues',
new_conditions_to_cover = 'new_conditions_to_cover',
new_coverage = 'new_coverage',
new_critical_violations = 'new_critical_violations',
+ new_software_quality_high_issues = 'new_software_quality_high_issues',
new_development_cost = 'new_development_cost',
new_duplicated_blocks = 'new_duplicated_blocks',
new_duplicated_lines = 'new_duplicated_lines',
new_duplicated_lines_density = 'new_duplicated_lines_density',
new_info_violations = 'new_info_violations',
+ new_software_quality_info_issues = 'new_software_quality_info_issues',
new_issues = 'new_issues',
new_line_coverage = 'new_line_coverage',
new_lines = 'new_lines',
new_maintainability_rating_distribution = 'new_maintainability_rating_distribution',
new_software_quality_maintainability_rating_distribution = 'new_software_quality_maintainability_rating_distribution',
new_major_violations = 'new_major_violations',
+ new_software_quality_medium_issues = 'new_software_quality_medium_issues',
new_minor_violations = 'new_minor_violations',
+ new_software_quality_low_issues = 'new_software_quality_low_issues',
new_reliability_issues = 'new_reliability_issues',
new_reliability_rating = 'new_reliability_rating',
new_software_quality_reliability_rating = 'new_software_quality_reliability_rating',
new_violations = 'new_violations',
new_violations_rating = 'new_violations_rating',
new_vulnerabilities = 'new_vulnerabilities',
+ new_software_quality_security_issues = 'new_software_quality_security_issues',
open_issues = 'open_issues',
prioritized_rule_issues = 'prioritized_rule_issues',
projects = 'projects',
violations = 'violations',
violations_rating = 'violations_rating',
vulnerabilities = 'vulnerabilities',
+ software_quality_security_issues = 'software_quality_security_issues',
wont_fix_issues = 'wont_fix_issues',
}
quality_gates.update_condition=Update Condition
quality_gates.condition_updated=Successfully updated condition.
quality_gates.conditions_updated=Successfully updated conditions.
+quality_gates.conditions_updated_to_the_mode=The metrics of "{qualityGateName}" gate were successfully updated
quality_gates.no_conditions=No Conditions
quality_gates.health_icons=Project health icons represent:
quality_gates.projects_for_default=Every project not specifically associated to a quality gate will be associated to this one by default.
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
+quality_gates.update_conditions.update_metrics=Update metrics
+quality_gates.update_conditions.header=Update all metrics of “{qualityGate}” gate
+quality_gates.update_conditions.header.single_metric=Update this metric
+quality_gates.update_conditions.description.line1=<b>Metrics</b> of the conditions listed below will be updated to align with the {mode} mode of this instance.
+quality_gates.update_conditions.description.line2=They will be calculated differently even if the names of the conditions persist between the Standard Experience and the MQR modes. <b>Operator</b> and <b>value</b> will remain unchanged.
+quality_gates.update_conditions.description.line3=Note that the update to {mode} might cause your quality gate to fail. {link}
+quality_gates.update_conditions.description.link=For more information, refer to the documentation.
+quality_gates.update_conditions.standard_mode_header=Standard Experience Metric
+quality_gates.update_conditions.mqr_mode_header=MQR Mode Metric
+quality_gates.update_conditions.operator_and_value_header=Operator and Value
+quality_gates.update_conditions.removed=Condition will be removed
+quality_gates.update_conditions.error=Failed to update some conditions
+
#------------------------------------------------------------------------------
#