<>
{id}
{Object.entries(values).map(([key, value]) => (
- <React.Fragment key={key}>{value}</React.Fragment>
+ <React.Fragment key={key}>
+ {typeof value === 'function' ? value() : value}
+ </React.Fragment>
))}
</>
);
},
formatDate: jest.fn().mockReturnValue(''),
}),
- FormattedMessage: ({ id, values }: { id: string; values?: { [x: string]: React.ReactNode } }) => {
+ FormattedMessage: ({
+ id,
+ values,
+ }: {
+ id: string;
+ values?: { [x: string]: React.ReactNode | (() => React.ReactNode) };
+ }) => {
return (
<>
{id}
{values !== undefined &&
Object.entries(values).map(([key, value]) => (
- <React.Fragment key={key}>{value}</React.Fragment>
+ <React.Fragment key={key}>
+ {typeof value === 'function' ? value() : value}
+ </React.Fragment>
))}
</>
);
import { cloneDeep, flatten, omit, remove } from 'lodash';
import { MetricKey } from '~sonar-aligned/types/metrics';
import { Project } from '../../apps/quality-gates/components/Projects';
+import { MQR_CONDITIONS_MAP, STANDARD_CONDITIONS_MAP } from '../../apps/quality-gates/utils';
import {
mockQualityGate,
mockQualityGateApplicationStatus,
error: '3',
},
],
+ hasStandardConditions: true,
+ hasMQRConditions: false,
isDefault: true,
isBuiltIn: false,
caycStatus: CaycStatus.Compliant,
error: '0',
isCaycCondition: true,
},
- { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eNy', metric: 'new_security_rating', op: 'GT', error: '0' },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eOl',
+ metric: MetricKey.new_software_quality_security_rating,
+ op: 'GT',
+ error: '1',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eOd',
+ metric: MetricKey.new_software_quality_security_rating,
+ op: 'GT',
+ error: '0',
+ },
{ id: 'deprecated', metric: 'function_complexity', op: 'LT', error: '1' },
],
isDefault: false,
isBuiltIn: false,
+ hasStandardConditions: false,
+ hasMQRConditions: true,
caycStatus: CaycStatus.NonCompliant,
}),
mockQualityGate({
name: 'Sonar way',
conditions: [
{
- id: 'AXJMbIUHPAOIsUIE3eNs',
+ id: 'AXJMbIUHPAOIsUIE3eQQ',
metric: 'new_violations',
op: 'GT',
error: '0',
],
isDefault: false,
isBuiltIn: true,
- caycStatus: CaycStatus.Compliant,
- hasStandardConditions: true,
+ hasStandardConditions: false,
hasMQRConditions: false,
+ caycStatus: CaycStatus.Compliant,
}),
mockQualityGate({
name: 'Non Cayc QG',
conditions: [
- { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eCC',
+ metric: MetricKey.new_software_quality_security_rating,
+ op: 'LT',
+ error: '80',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eOD',
+ metric: MetricKey.new_software_quality_reliability_rating,
+ op: 'LT',
+ error: '80',
+ },
+ { id: 'AXJMbIUHPAOIsUIE3eOA', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
],
isDefault: false,
isBuiltIn: false,
mockQualityGate({
name: 'Non Cayc Compliant QG',
conditions: [
- { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'new_security_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eOD', metric: 'new_reliability_rating', op: 'GT', error: '1' },
- { id: 'AXJMbIUHPAOIsUIE3eOF', metric: 'new_coverage', op: 'LT', error: '80' },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eDD',
+ metric: MetricKey.new_software_quality_security_rating,
+ op: 'GT',
+ error: '1',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eDA',
+ metric: MetricKey.new_software_quality_reliability_rating,
+ op: 'GT',
+ error: '1',
+ },
+ { id: 'AXJMbIUHPAOIsUIE3eDK', metric: MetricKey.new_coverage, op: 'LT', error: '80' },
],
isDefault: false,
isBuiltIn: false,
+ hasStandardConditions: false,
+ hasMQRConditions: true,
caycStatus: CaycStatus.Compliant,
}),
mockQualityGate({
],
isDefault: false,
isBuiltIn: false,
+ hasStandardConditions: true,
+ hasMQRConditions: false,
caycStatus: CaycStatus.OverCompliant,
}),
mockQualityGate({
conditions: [],
isDefault: false,
isBuiltIn: false,
+ hasStandardConditions: false,
+ hasMQRConditions: false,
caycStatus: CaycStatus.NonCompliant,
}),
mockQualityGate({
name: 'QG without new code conditions',
conditions: [
- { id: 'AXJMbIUHPAOIsUIE3eNs', metric: 'security_rating', op: 'GT', error: '1' },
+ { id: 'AXJMbIUHPAOIsUIE3eAA', metric: 'security_rating', op: 'GT', error: '1' },
],
isDefault: false,
isBuiltIn: false,
+ hasStandardConditions: true,
+ hasMQRConditions: false,
+ caycStatus: CaycStatus.NonCompliant,
+ }),
+ mockQualityGate({
+ name: 'QG with MQR conditions',
+ conditions: [
+ {
+ id: 'AXJMbIUHPAOIsUIE3eWW',
+ metric: MetricKey.software_quality_security_rating,
+ op: 'GT',
+ error: '1',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eW1',
+ metric: MetricKey.new_software_quality_blocker_issues,
+ op: 'GT',
+ error: '1',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eW2',
+ metric: MetricKey.new_software_quality_high_issues,
+ op: 'GT',
+ error: '1',
+ },
+ {
+ id: 'AXJMbIUHPAOIsUIE3eW3',
+ metric: MetricKey.high_impact_accepted_issues,
+ op: 'GT',
+ error: '1',
+ },
+ ],
+ isDefault: false,
+ isBuiltIn: false,
+ hasStandardConditions: false,
+ hasMQRConditions: true,
caycStatus: CaycStatus.NonCompliant,
}),
];
conditions.push(newCondition);
qg.conditions = conditions;
+ qg.hasMQRConditions =
+ qg.hasMQRConditions || MQR_CONDITIONS_MAP[metric as MetricKey] !== undefined;
+ qg.hasStandardConditions =
+ qg.hasStandardConditions || STANDARD_CONDITIONS_MAP[metric as MetricKey] !== undefined;
return this.reply(newCondition);
};
condition.error = error;
condition.isCaycCondition = isCaycCondition;
+ const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
+
+ if (qg) {
+ qg.hasMQRConditions =
+ qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+ false;
+ qg.hasStandardConditions =
+ qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+ false;
+ }
+
return this.reply(condition);
};
this.list.forEach((q) => {
remove(q.conditions || [], (c) => c.id === id);
});
+
+ const qg = this.list.find((qg) => qg.conditions?.find((c) => c.id === id));
+
+ if (qg) {
+ qg.hasMQRConditions =
+ qg.conditions?.some((c) => MQR_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+ false;
+ qg.hasStandardConditions =
+ qg.conditions?.some((c) => STANDARD_CONDITIONS_MAP[c.metric as MetricKey] !== undefined) ||
+ false;
+ }
+
return Promise.resolve();
};
await user.click(ui.maintainabilityDomainBtn.get());
[
'component_measures.metric.new_maintainability_issues.name 5',
- 'Software Quality Maintainability Remediation Effort on new code work_duration.x_minutes.1',
- 'Software Quality Technical Debt Ratio on New Code 1.0%',
- 'Software Quality Maintainability Rating on New Code metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+ '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.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
'component_measures.metric.maintainability_issues.name 2',
- 'Software Quality Maintainability Remediation Effort work_duration.x_minutes.1',
- 'Software Quality Technical Debt Ratio 1.0%',
- 'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
- 'Software Quality Effort to Reach Maintainability Rating A work_duration.x_minutes.1',
+ 'Technical Debt work_duration.x_minutes.1',
+ 'Technical Debt Ratio 1.0%',
+ 'Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+ 'Effort to Reach Maintainability Rating A work_duration.x_minutes.1',
].forEach((measure) => {
expect(ui.measureLink(measure).get()).toBeInTheDocument();
});
await user.click(
ui
.measureLink(
- 'Software Quality Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
+ 'Maintainability Rating metric.has_rating_X.D metric.software_quality_maintainability_rating.tooltip.D.0.0%',
)
.get(),
);
renderProjectLinksApp();
await ui.appIsLoaded();
- expect(ui.noResultsTable.get()).toBeInTheDocument();
+ expect(await ui.noResultsTable.find()).toBeInTheDocument();
// Create link
await ui.createLink(newLinkName1, 'https://link.com');
ButtonSize,
ButtonVariety,
IconDelete,
+ IconRefresh,
ModalAlert,
} from '@sonarsource/echoes-react';
-import { ActionCell, ContentCell, NumericalCell, TableRow, TextError } from '~design-system';
+import { useIntl } from 'react-intl';
+import {
+ ActionCell,
+ ContentCell,
+ NumericalCell,
+ Pill,
+ PillHighlight,
+ PillVariant,
+ TableRow,
+ TextError,
+} from '~design-system';
import { useMetrics } from '../../../app/components/metrics/withMetricsContext';
import { getLocalizedMetricName, translate, translateWithParameters } from '../../../helpers/l10n';
import { getOperatorLabel } from '../../../helpers/qualityGates';
import { useDeleteConditionMutation } from '../../../queries/quality-gates';
+import { useStandardExperienceMode } from '../../../queries/settings';
import { MetricKey } from '../../../sonar-aligned/types/metrics';
import { CaycStatus, Condition as ConditionType, Metric, QualityGate } from '../../../types/types';
import {
getLocalizedMetricNameNoDiffMetric,
isConditionWithFixedValue,
isNonEditableMetric,
+ MQR_CONDITIONS_MAP,
+ STANDARD_CONDITIONS_MAP,
} from '../utils';
import ConditionValue from './ConditionValue';
import EditConditionModal from './EditConditionModal';
+import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
export enum ConditionChange {
Added = 'added',
}: Readonly<Props>) {
const { mutateAsync: deleteCondition } = useDeleteConditionMutation(qualityGate.name);
const metrics = useMetrics();
+ const intl = useIntl();
+ const { data: isStandard } = useStandardExperienceMode();
const { op = 'GT' } = condition;
const isCaycCompliantAndOverCompliant = qualityGate.caycStatus !== CaycStatus.NonCompliant;
+ const isMetricFromOtherMode = isStandard
+ ? MQR_CONDITIONS_MAP[condition.metric as MetricKey] !== undefined
+ : STANDARD_CONDITIONS_MAP[condition.metric as MetricKey] !== undefined;
return (
<TableRow>
<ContentCell>
{getLocalizedMetricNameNoDiffMetric(metric, metrics)}
+ {isMetricFromOtherMode && canEdit && (
+ <Pill className="sw-ml-2" variant={PillVariant.Neutral} highlight={PillHighlight.Medium}>
+ {intl.formatMessage({
+ id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_short`,
+ })}
+ </Pill>
+ )}
{metric.hidden && <TextError className="sw-ml-1" text={translate('deprecated')} />}
</ContentCell>
<ActionCell>
{!isCaycModal && canEdit && (
<>
+ {isMetricFromOtherMode && (
+ <UpdateConditionsFromOtherModeModal
+ condition={condition}
+ qualityGateName={qualityGate.name}
+ >
+ <ButtonIcon
+ Icon={IconRefresh}
+ variety={ButtonVariety.PrimaryGhost}
+ className="sw-mr-4"
+ ariaLabel={intl.formatMessage(
+ { id: 'quality_gates.mqr_mode_update.single_metric.tooltip.message' },
+ {
+ metric: getLocalizedMetricNameNoDiffMetric(metric, metrics),
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+ }),
+ },
+ )}
+ />
+ </UpdateConditionsFromOtherModeModal>
+ )}
{(!isCaycCompliantAndOverCompliant ||
!isConditionWithFixedValue(condition) ||
(isCaycCompliantAndOverCompliant && showEdit)) &&
- !isNonEditableMetric(condition.metric as MetricKey) && (
+ !isNonEditableMetric(condition.metric as MetricKey) &&
+ !isMetricFromOtherMode && (
<EditConditionModal
condition={condition}
header={translate('quality_gates.update_condition')}
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-import { Button, Spinner } from '@sonarsource/echoes-react';
+import { Spinner } from '@sonarsource/echoes-react';
import { uniqBy } from 'lodash';
import * as React from 'react';
import { FormattedMessage } from 'react-intl';
import CaycReviewUpdateConditionsModal from './ConditionReviewAndUpdateModal';
import ConditionsTable from './ConditionsTable';
import QGRecommendedIcon from './QGRecommendedIcon';
-import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
+import UpdateConditionsFromOtherModeBanner from './UpdateConditionsFromOtherModeBanner';
interface Props {
isFetching?: boolean;
);
const conditionsToOtherModeMap = isStandardMode ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+ const hasConditionsFromOtherMode =
+ qualityGate[isStandardMode ? 'hasMQRConditions' : 'hasStandardConditions'];
return (
<Spinner isLoading={isLoading}>
</LightLabel>
</div>
)}
- {isCompliantCustomQualityGate && !isOptimizing && <CaycCompliantBanner />}
- {isCompliantCustomQualityGate && isOptimizing && canEdit && (
+ {(!hasConditionsFromOtherMode || !canEdit) &&
+ isCompliantCustomQualityGate &&
+ !isOptimizing && <CaycCompliantBanner />}
+ {!hasConditionsFromOtherMode && isCompliantCustomQualityGate && isOptimizing && canEdit && (
<CaycFixOptimizeBanner renderCaycModal={renderCaycModal} isOptimizing />
)}
- {caycStatus === CaycStatus.NonCompliant && canEdit && (
+ {!hasConditionsFromOtherMode && 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>
+ {hasConditionsFromOtherMode && canEdit && (
+ <UpdateConditionsFromOtherModeBanner
+ qualityGateName={qualityGate.name}
+ newCodeConditions={newCodeConditions.filter(
+ (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+ )}
+ overallCodeConditions={overallCodeConditions.filter(
+ (c) => conditionsToOtherModeMap[c.metric as MetricKey] !== undefined,
+ )}
+ />
+ )}
+
<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">
{newCodeConditions.length > 0 && (
<div>
- <HeadingDark as="h3" className="sw-mb-2">
- {translate('quality_gates.conditions.new_code', 'long')}
- </HeadingDark>
+ <div className="sw-flex sw-justify-between">
+ <HeadingDark className="sw-mb-2">
+ {translate('quality_gates.conditions.new_code', 'long')}
+ </HeadingDark>
+ {hasFeature(Feature.BranchSupport) && (
+ <Note className="sw-mb-2 sw-typo-default">
+ {translate('quality_gates.conditions.new_code', 'description')}
+ </Note>
+ )}
+ </div>
<ConditionsTable
qualityGate={qualityGate}
showEdit={editing}
scope="new"
/>
-
- {hasFeature(Feature.BranchSupport) && (
- <Note className="sw-mb-2 sw-typo-default">
- {translate('quality_gates.conditions.new_code', 'description')}
- </Note>
- )}
</div>
)}
{overallCodeConditions.length > 0 && (
<div className="sw-mt-5">
- <HeadingDark as="h3" className="sw-mb-2">
- {translate('quality_gates.conditions.overall_code', 'long')}
- </HeadingDark>
+ <div className="sw-flex sw-justify-between">
+ <HeadingDark className="sw-mb-2">
+ {translate('quality_gates.conditions.overall_code', 'long')}
+ </HeadingDark>
+ {hasFeature(Feature.BranchSupport) && (
+ <Note className="sw-mb-2 sw-typo-default">
+ {translate('quality_gates.conditions.overall_code', 'description')}
+ </Note>
+ )}
+ </div>
<ConditionsTable
qualityGate={qualityGate}
conditions={overallCodeConditions}
scope="overall"
/>
-
- {hasFeature(Feature.BranchSupport) && (
- <Note className="sw-mb-2 sw-typo-default">
- {translate('quality_gates.conditions.overall_code', 'description')}
- </Note>
- )}
</div>
)}
</div>
return (
<Table
columnCount={4}
- columnWidths={['300px', 'auto', 'auto', 'auto']}
+ columnWidths={['auto', '150px', '150px', '200px']}
className="sw-my-2"
header={<Header />}
data-test={`quality-gates__conditions-${scope}`}
const isBuiltInTitle = isBuiltIn ? ` ${translate('quality_gates.built_in')}` : '';
const isAICodeAssuranceQualityGate =
hasFeature(Feature.AiCodeAssurance) && isBuiltIn && name === 'Sonar way';
+
const shouldShowQualityGateUpdateIcon =
actions?.manageConditions === true &&
((isStandard && hasMQRConditions === true) ||
--- /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, IconRefresh } from '@sonarsource/echoes-react';
+import { FormattedMessage, useIntl } from 'react-intl';
+import { CardWithPrimaryBackground, SubHeadingHighlight } from '~design-system';
+import DocumentationLink from '../../../components/common/DocumentationLink';
+import { DocLink } from '../../../helpers/doc-links';
+import { useStandardExperienceMode } from '../../../queries/settings';
+import { Condition } from '../../../types/types';
+import UpdateConditionsFromOtherModeModal from './UpdateConditionsFromOtherModeModal';
+
+interface Props {
+ newCodeConditions: Condition[];
+ overallCodeConditions: Condition[];
+ qualityGateName: string;
+}
+
+export default function UpdateConditionsFromOtherModeBanner(props: Readonly<Props>) {
+ const { data: isStandard } = useStandardExperienceMode();
+ const intl = useIntl();
+ return (
+ <CardWithPrimaryBackground className="sw-mt-9 sw-p-8">
+ <SubHeadingHighlight className="sw-mb-2">
+ {intl.formatMessage(
+ { id: 'quality_gates.mode_banner.title' },
+ {
+ mode: intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+ }),
+ },
+ )}
+ </SubHeadingHighlight>
+ <div>
+ <FormattedMessage
+ id="quality_gates.mode_banner.description"
+ values={{
+ link: (
+ <DocumentationLink to={isStandard ? DocLink.ModeStandard : DocLink.ModeMQR}>
+ {intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'standard' : 'mqr'}.name`,
+ })}
+ </DocumentationLink>
+ ),
+ otherMode: intl.formatMessage({
+ id: `settings.mode.${isStandard ? 'mqr' : 'standard'}.name`,
+ }),
+ }}
+ />
+ </div>
+ <UpdateConditionsFromOtherModeModal {...props}>
+ <Button className="sw-mt-4" prefix={<IconRefresh />} variety={ButtonVariety.Primary}>
+ {intl.formatMessage({ id: 'quality_gates.mode_banner.button' })}
+ </Button>
+ </UpdateConditionsFromOtherModeModal>
+ </CardWithPrimaryBackground>
+ );
+}
type Props = React.PropsWithChildren & { qualityGateName: string } & (
| {
condition?: never;
- isSingleMetric?: false;
newCodeConditions: Condition[];
overallCodeConditions: Condition[];
}
| {
condition: Condition;
- isSingleMetric: true;
newCodeConditions?: never;
overallCodeConditions?: never;
}
newCodeConditions,
overallCodeConditions,
qualityGateName,
- isSingleMetric,
condition,
children,
}: Readonly<Props>) {
const [error, setError] = React.useState(false);
const intl = useIntl();
const mapper = isStandard ? MQR_CONDITIONS_MAP : STANDARD_CONDITIONS_MAP;
+ const isSingleMetric = !!condition;
const { mutate: updateConditions, isPending } = useUpdateOrDeleteConditionsMutation(
qualityGateName,
isSingleMetric,
{intl.formatMessage({ id: 'overview.new_code' })}
</Heading>
<Table
+ data-testid="quality-gates__conditions-new"
columnCount={3}
columnWidths={['35%', '35%', 'auto']}
className="sw-my-2"
{intl.formatMessage({ id: 'overview.overall_code' })}
</Heading>
<Table
+ data-testid="quality-gates__conditions-overall"
columnCount={3}
columnWidths={['35%', '35%', 'auto']}
className="sw-my-2"
<div>
<Text as="div" size={TextSize.Small}>
{intl.formatMessage({
- id: `quality_gates.update_conditions.${isStandard ? 'mqr' : 'standard'}_mode_header`,
+ id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_long`,
})}
</Text>
<Text as="div" size={TextSize.Small} isHighlighted>
<>
<Text as="div" size={TextSize.Small}>
{intl.formatMessage({
- id: `quality_gates.update_conditions.${isStandard ? 'standard' : 'mqr'}_mode_header`,
+ id: `quality_gates.metric.${isStandard ? 'standard' : 'mqr'}_mode_long`,
})}
</Text>
<Text as="div" size={TextSize.Small} isHighlighted>
</Text>
</>
) : (
- <Text size={TextSize.Small}>
+ <Text size={TextSize.Small} colorOverride="echoes-color-text-danger">
{intl.formatMessage({ id: 'quality_gates.update_conditions.removed' })}
</Text>
)}
<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`,
+ id: `quality_gates.metric.${isStandard ? 'mqr' : 'standard'}_mode_long`,
})}
</Heading>
<IconArrowRight />
<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`,
+ id: `quality_gates.metric.${isStandard ? 'standard' : 'mqr'}_mode_long`,
})}
</Heading>
</ContentCell>
import { screen, waitFor, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
-import { byLabelText, byRole, byTestId } from '~sonar-aligned/helpers/testSelector';
+import { byLabelText, byRole, byTestId, byText } from '~sonar-aligned/helpers/testSelector';
import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock';
import SettingsServiceMock from '../../../../api/mocks/SettingsServiceMock';
import UsersServiceMock from '../../../../api/mocks/UsersServiceMock';
import { NoticeType } from '../../../../types/users';
import routes from '../../routes';
+const ui = {
+ batchUpdate: byRole('button', { name: 'quality_gates.mode_banner.button' }),
+ singleUpdate: byRole('button', {
+ name: /quality_gates.mqr_mode_update.single_metric.tooltip.message/,
+ }),
+ removeCondition: byRole('button', { name: /quality_gates.condition.delete/ }),
+ listItem: byTestId('js-subnavigation-item'),
+ requiresUpdateIndicator: byTestId('quality-gates-mqr-standard-mode-update-indicator'),
+ qualityGateListItem: (qualityGateName: string) => byRole('link', { name: qualityGateName }),
+ newConditionRow: byTestId('quality-gates__conditions-new').byRole('row'),
+ overallConditionRow: byTestId('quality-gates__conditions-overall').byRole('row'),
+ batchDialog: byRole('dialog', { name: /quality_gates.update_conditions.header/ }),
+ singleDialog: byRole('dialog', { name: /quality_gates.update_conditions.header.single_metric/ }),
+ updateMetricsBtn: byRole('button', { name: 'quality_gates.update_conditions.update_metrics' }),
+ updateSingleBtn: byRole('button', { name: 'update_verb' }),
+ cancelBtn: byRole('button', { name: 'cancel' }),
+ standardBadge: byText('quality_gates.metric.standard_mode_short'),
+ mqrBadge: byText('quality_gates.metric.mqr_mode_short'),
+};
+
let qualityGateHandler: QualityGatesServiceMock;
let usersHandler: UsersServiceMock;
let settingsHandler: SettingsServiceMock;
qualityGateHandler.setIsAdmin(true);
renderQualityGateApp();
- expect(
- await screen.findByTestId('quality-gates-mqr-standard-mode-update-indicator'),
- ).toBeInTheDocument();
+ expect(await ui.requiresUpdateIndicator.findAll()).toHaveLength(3);
});
it('should show Standard mode update icon if MQR mode conditions are present', async () => {
qualityGateHandler.setIsAdmin(true);
renderQualityGateApp();
- expect(
- await screen.findByTestId('quality-gates-mqr-standard-mode-update-indicator'),
- ).toBeInTheDocument();
+ expect(await ui.requiresUpdateIndicator.findAll()).toHaveLength(4);
});
it('should render the built-in quality gate properly', async () => {
);
// In real app there are no metrics with selectable condition operator
- // so we manually changed direction for Info Issues to 0 to test this behavior
- await user.click(await dialog.byRole('option', { name: 'Info Issues' }).find());
+ // so we manually changed direction for Cognitive Complexity to 0 to test this behavior
+ await user.click(await dialog.byRole('option', { name: 'Cognitive Complexity' }).find());
await user.click(await dialog.byLabelText('quality_gates.conditions.operator').find());
const overallConditions = byTestId('quality-gates__conditions-overall');
expect(
- await overallConditions.byRole('cell', { name: 'Info Issues' }).find(),
+ await overallConditions.byRole('cell', { name: 'Cognitive Complexity' }).find(),
).toBeInTheDocument();
expect(await overallConditions.byRole('cell', { name: '42' }).find()).toBeInTheDocument();
});
const overallConditions = byTestId('quality-gates__conditions-overall');
expect(
- await overallConditions.byRole('cell', { name: 'Maintainability Rating' }).find(),
+ await overallConditions.byRole('cell', { name: /Maintainability Rating/ }).find(),
).toBeInTheDocument();
expect(await overallConditions.byRole('cell', { name: 'B' }).find()).toBeInTheDocument();
});
});
});
+describe('Mode transition', () => {
+ describe('MQR mode', () => {
+ it('should not see that quality gates require updates if not an admin', async () => {
+ const user = userEvent.setup();
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ expect(ui.requiresUpdateIndicator.query()).not.toBeInTheDocument();
+ await user.click(ui.qualityGateListItem('SonarSource way default').get());
+ expect(byText('quality_gates.cayc.banner.title').get()).toBeInTheDocument();
+ expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+ expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+ expect(ui.standardBadge.query()).not.toBeInTheDocument();
+ });
+
+ it('should see that quality gates require updates if an admin', async () => {
+ const user = userEvent.setup();
+ qualityGateHandler.setIsAdmin(true);
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ expect(
+ ui.qualityGateListItem('SonarSource way default').by(ui.requiresUpdateIndicator).get(),
+ ).toBeInTheDocument();
+ await user.click(ui.qualityGateListItem('SonarSource way default').get());
+ expect(byText('quality_gates.cayc.banner.title').query()).not.toBeInTheDocument();
+ expect(ui.batchUpdate.get()).toBeInTheDocument();
+ expect(ui.singleUpdate.getAll()).toHaveLength(5);
+ expect(ui.standardBadge.getAll()).toHaveLength(5);
+ });
+
+ it('should update conditions to MQR mode', async () => {
+ const user = userEvent.setup();
+ qualityGateHandler.setIsAdmin(true);
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ await user.click(ui.qualityGateListItem('SonarSource way default').get());
+
+ await user.click(ui.batchUpdate.get());
+ expect(ui.batchDialog.get()).toBeInTheDocument();
+ // + 1 for headers
+ expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(4);
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+ await user.click(ui.batchDialog.by(ui.cancelBtn).get());
+
+ expect(ui.newConditionRow.getAt(7)).toHaveTextContent(
+ 'Reliability Ratingquality_gates.metric.standard_mode_short',
+ );
+ expect(ui.singleUpdate.get(ui.newConditionRow.getAt(7))).toBeInTheDocument();
+ await user.click(ui.singleUpdate.get(ui.newConditionRow.getAt(7)));
+ expect(ui.singleDialog.get()).toBeInTheDocument();
+ expect(ui.singleDialog.get()).toHaveTextContent(
+ 'quality_gates.metric.standard_mode_longReliability Ratingquality_gates.metric.mqr_mode_longReliability Rating',
+ );
+ await user.click(ui.updateSingleBtn.get());
+
+ expect(ui.singleUpdate.getAll()).toHaveLength(4);
+ expect(ui.standardBadge.getAll()).toHaveLength(4);
+
+ await user.click(ui.batchUpdate.get());
+ expect(ui.batchDialog.get()).toBeInTheDocument();
+ // + 1 for headers
+ expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(3);
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+ expect(ui.batchDialog.by(ui.newConditionRow).getAt(1)).toHaveTextContent(
+ 'Maintainability RatingMaintainability Rating',
+ );
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAt(1)).toHaveTextContent(
+ 'Reliability RatingReliability Rating',
+ );
+ await user.click(ui.batchDialog.by(ui.updateMetricsBtn).get());
+
+ expect(byText('quality_gates.cayc.banner.title').get()).toBeInTheDocument();
+ expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+ expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+ expect(ui.standardBadge.query()).not.toBeInTheDocument();
+ });
+ });
+
+ describe('Standard mode', () => {
+ beforeEach(() => {
+ settingsHandler.set(SettingsKey.MQRMode, 'false');
+ });
+
+ it('should not see that quality gates require updates if not an admin', async () => {
+ const user = userEvent.setup();
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ expect(ui.requiresUpdateIndicator.query()).not.toBeInTheDocument();
+ await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+ expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+ expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+ expect(ui.mqrBadge.query()).not.toBeInTheDocument();
+ });
+
+ it('should see that quality gates require updates if an admin', async () => {
+ const user = userEvent.setup();
+ qualityGateHandler.setIsAdmin(true);
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ expect(
+ ui.qualityGateListItem('QG with MQR conditions').by(ui.requiresUpdateIndicator).get(),
+ ).toBeInTheDocument();
+ await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+ expect(ui.batchUpdate.get()).toBeInTheDocument();
+ expect(ui.singleUpdate.getAll()).toHaveLength(4);
+ expect(ui.mqrBadge.getAll()).toHaveLength(4);
+ });
+
+ it('should update conditions to Standard mode', async () => {
+ const user = userEvent.setup();
+ qualityGateHandler.setIsAdmin(true);
+ renderQualityGateApp();
+
+ expect(await ui.listItem.findAll()).toHaveLength(9);
+ await user.click(ui.qualityGateListItem('QG with MQR conditions').get());
+
+ await user.click(ui.batchUpdate.get());
+ expect(ui.batchDialog.get()).toBeInTheDocument();
+ // + 1 for headers
+ expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(3);
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+ await user.click(ui.batchDialog.by(ui.cancelBtn).get());
+
+ expect(ui.newConditionRow.getAt(1)).toHaveTextContent(
+ 'Blocker Severity Issuesquality_gates.metric.mqr_mode_short',
+ );
+ expect(ui.singleUpdate.get(ui.newConditionRow.getAt(1))).toBeInTheDocument();
+ await user.click(ui.singleUpdate.get(ui.newConditionRow.getAt(1)));
+ expect(ui.singleDialog.get()).toBeInTheDocument();
+ expect(ui.singleDialog.get()).toHaveTextContent(
+ 'quality_gates.metric.mqr_mode_longBlocker Severity Issuesquality_gates.metric.standard_mode_longBlocker Issues',
+ );
+ await user.click(ui.updateSingleBtn.get());
+
+ expect(ui.singleUpdate.getAll()).toHaveLength(3);
+ expect(ui.mqrBadge.getAll()).toHaveLength(3);
+
+ await user.click(ui.batchUpdate.get());
+ expect(ui.batchDialog.get()).toBeInTheDocument();
+ // + 1 for headers
+ expect(ui.batchDialog.by(ui.newConditionRow).getAll()).toHaveLength(2);
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAll()).toHaveLength(3);
+ expect(ui.batchDialog.by(ui.newConditionRow).getAt(1)).toHaveTextContent(
+ 'High Severity IssuesCritical Issues',
+ );
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAt(1)).toHaveTextContent(
+ 'Blocker and High Severity Accepted Issuesquality_gates.update_conditions.removed',
+ );
+ expect(ui.batchDialog.by(ui.overallConditionRow).getAt(2)).toHaveTextContent(
+ 'Security RatingSecurity Rating',
+ );
+ await user.click(ui.batchDialog.by(ui.updateMetricsBtn).get());
+
+ expect(byText('quality_gates.cayc_missing.banner.title').get()).toBeInTheDocument();
+ expect(ui.batchUpdate.query()).not.toBeInTheDocument();
+ expect(ui.singleUpdate.query()).not.toBeInTheDocument();
+ expect(ui.mqrBadge.query()).not.toBeInTheDocument();
+ });
+ });
+});
+
function renderQualityGateApp(context?: RenderContext) {
return renderAppRoutes('quality_gates', routes, context);
}
qualitative: true,
hidden: false,
},
+ new_software_quality_maintainability_remediation_effort: {
+ id: 'bf182476-9397-4471-812d-7e40568ef1b0',
+ key: 'new_software_quality_maintainability_remediation_effort',
+ type: 'WORK_DUR',
+ name: 'Added Technical Debt',
+ description:
+ 'Total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
analysis_from_sonarqube_9_4: {
id: 'AX_iDGfBRf9uEywNDdeh',
key: 'analysis_from_sonarqube_9_4',
qualitative: false,
hidden: true,
},
+ high_impact_accepted_issues: {
+ id: 'AY0aC41wVDhd53-OniNc',
+ key: 'high_impact_accepted_issues',
+ type: 'INT',
+ name: 'Blocker and High Severity Accepted Issues',
+ description: 'Accepted issues with blocker or high impact',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: false,
+ hidden: false,
+ },
blocker_violations: {
id: 'AXJMbIl_PAOIsUIE3gtt',
key: 'blocker_violations',
qualitative: true,
hidden: false,
},
+ software_quality_blocker_issues: {
+ id: '9a1650ae-056f-4d40-b761-0ae06b9f15b2',
+ key: 'software_quality_blocker_issues',
+ type: 'INT',
+ name: 'Blocker Severity Issues',
+ description: 'Blocker Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
bugs: {
id: 'AXJMbIl_PAOIsUIE3gt_',
key: 'bugs',
name: 'Cognitive Complexity',
description: 'Cognitive complexity',
domain: 'Complexity',
- direction: -1,
+ direction: 0, // manually changed direction to test quality gate condition operator
qualitative: false,
hidden: false,
},
qualitative: false,
hidden: false,
},
+ effort_to_reach_software_quality_maintainability_rating_a: {
+ id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551',
+ key: 'effort_to_reach_software_quality_maintainability_rating_a',
+ type: 'WORK_DUR',
+ name: 'Effort to Reach Maintainability Rating A',
+ description: 'Effort to reach maintainability rating A',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
effort_to_reach_maintainability_rating_a: {
id: 'AXJMbIl_PAOIsUIE3guM',
key: 'effort_to_reach_maintainability_rating_a',
qualitative: false,
hidden: false,
},
- high_impact_accepted_issues: {
- id: 'AY0aC41wVDhd53-OniNc',
- key: 'high_impact_accepted_issues',
+ software_quality_high_issues: {
+ id: '50f6240a-85c5-4aaf-a928-657c7f03b6ef',
+ key: 'software_quality_high_issues',
type: 'INT',
- name: 'Blocker and High Severity Accepted Issues',
- description: 'Accepted issues with blocker or high impact',
+ name: 'High Severity Issues',
+ description: 'High Severity issues',
domain: 'Issues',
direction: -1,
- qualitative: false,
+ qualitative: true,
hidden: false,
},
info_violations: {
name: 'Info Issues',
description: 'Info issues',
domain: 'Issues',
- direction: 0, // manually changed direction to test quality gate condition operator
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
+ software_quality_info_issues: {
+ id: 'cfc48499-476f-43fb-999e-43bb33e7c93a',
+ key: 'software_quality_info_issues',
+ type: 'INT',
+ name: 'Info Severity Issues',
+ description: 'Info Severity issues',
+ domain: 'Issues',
+ direction: -1,
qualitative: true,
hidden: false,
},
qualitative: false,
hidden: true,
},
- last_change_on_software_quality_releasability_rating: {
- id: 'a2aebcc4-366d-49b3-852b-c7b36f43e1c7',
- key: 'last_change_on_software_quality_releasability_rating',
- type: 'DATA',
- name: 'Last Change on Software Quality Releasability Rating',
- domain: 'Releasability',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
last_change_on_software_quality_reliability_rating: {
id: '42889539-14b7-45a5-a383-8c4d4a5e48a5',
key: 'last_change_on_software_quality_reliability_rating',
qualitative: false,
hidden: true,
},
- last_change_on_software_quality_security_review_rating: {
- id: '0f4f143d-b76b-40c9-8769-7f959f4a49ea',
- key: 'last_change_on_software_quality_security_review_rating',
- type: 'DATA',
- name: 'Last Change on SoftwareQuality Security Review Rating',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
line_coverage: {
id: 'AXJMbIl_PAOIsUIE3gtl',
key: 'line_coverage',
qualitative: false,
hidden: true,
},
+ software_quality_low_issues: {
+ id: '452a1f9d-c0c6-4001-b5ce-921b748423e2',
+ key: 'software_quality_low_issues',
+ type: 'INT',
+ name: 'Low Severity Issues',
+ description: 'Low Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
maintainability_issues: {
id: 'acc8fd75-3acf-499f-809c-f104af89d16d',
key: 'maintainability_issues',
qualitative: false,
hidden: false,
},
+ software_quality_maintainability_issues: {
+ id: '163c2107-797a-46c8-a1a9-912b00dae7df',
+ key: 'software_quality_maintainability_issues',
+ type: 'INT',
+ name: 'Maintainability Issues',
+ description: 'Maintainability Issues',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: false,
+ hidden: false,
+ },
+ software_quality_maintainability_rating: {
+ id: '9fc76baf-f660-4f65-a271-b2ae7f849239',
+ key: 'software_quality_maintainability_rating',
+ type: 'RATING',
+ name: 'Maintainability Rating',
+ description: 'Maintainability rating',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
sqale_rating: {
id: 'AXJMbIl_PAOIsUIE3guF',
key: 'sqale_rating',
qualitative: true,
hidden: true,
},
+ new_software_quality_maintainability_rating: {
+ id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e',
+ key: 'new_software_quality_maintainability_rating',
+ type: 'RATING',
+ name: 'Maintainability Rating on New Code',
+ description: 'Maintainability rating on new code',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_maintainability_rating: {
id: 'AXJMbIl_PAOIsUIE3guH',
key: 'new_maintainability_rating',
qualitative: true,
hidden: false,
},
+ software_quality_medium_issues: {
+ id: '5c85ee75-753a-44db-b357-5ea54cd2d88b',
+ key: 'software_quality_medium_issues',
+ type: 'INT',
+ name: 'Medium Severity Issues',
+ description: 'Medium Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
minor_violations: {
id: 'AXJMbIl_PAOIsUIE3gtw',
key: 'minor_violations',
qualitative: true,
hidden: false,
},
+ new_software_quality_blocker_issues: {
+ id: '24492b83-d35f-4cbd-b12f-0b1168cb7c9a',
+ key: 'new_software_quality_blocker_issues',
+ type: 'INT',
+ name: 'New Blocker Severity Issues',
+ description: 'New Blocker Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_bugs: {
id: 'AXJMbIl_PAOIsUIE3guA',
key: 'new_bugs',
qualitative: true,
hidden: false,
},
+ new_software_quality_high_issues: {
+ id: '1f2e2f4d-4069-4998-885b-287cb87939b6',
+ key: 'new_software_quality_high_issues',
+ type: 'INT',
+ name: 'New High Severity Issues',
+ description: 'New High Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_info_violations: {
id: 'AXJMbIl_PAOIsUIE3gt3',
key: 'new_info_violations',
qualitative: true,
hidden: false,
},
+ new_software_quality_info_issues: {
+ id: '6857dd13-4d48-4a6f-b985-889930ee3508',
+ key: 'new_software_quality_info_issues',
+ type: 'INT',
+ name: 'New Info Severity Issues',
+ description: 'New Info Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_violations: {
id: 'AXJMbIl_PAOIsUIE3gty',
key: 'new_violations',
qualitative: false,
hidden: false,
},
+ new_software_quality_low_issues: {
+ id: '8ecc3d65-72e7-4a36-9d1b-84344ba017f3',
+ key: 'new_software_quality_low_issues',
+ type: 'INT',
+ name: 'New Low Severity Issues',
+ description: 'New Low Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_maintainability_issues: {
id: '9385d0e6-8991-40b1-b94a-5a260e6146f0',
key: 'new_maintainability_issues',
qualitative: false,
hidden: false,
},
+ new_software_quality_maintainability_issues: {
+ id: 'e0216417-de54-4beb-8948-f61bd53987ed',
+ key: 'new_software_quality_maintainability_issues',
+ type: 'INT',
+ name: 'New Maintainability Issues',
+ description: 'New Maintainability Issues',
+ domain: 'Maintainability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_major_violations: {
id: 'AXJMbIl_PAOIsUIE3gt1',
key: 'new_major_violations',
qualitative: true,
hidden: false,
},
+ new_software_quality_medium_issues: {
+ id: '9d634fca-caee-4bee-8e23-37744d014194',
+ key: 'new_software_quality_medium_issues',
+ type: 'INT',
+ name: 'New Medium Severity Issues',
+ description: 'New Medium Severity issues',
+ domain: 'Issues',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_minor_violations: {
id: 'AXJMbIl_PAOIsUIE3gt2',
key: 'new_minor_violations',
qualitative: false,
hidden: false,
},
+ new_software_quality_reliability_issues: {
+ id: 'bfcac26d-2ce7-4fbf-b5c6-ea4f6556825d',
+ key: 'new_software_quality_reliability_issues',
+ type: 'INT',
+ name: 'New Reliability Issues',
+ description: 'New Reliability Issues',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_security_hotspots: {
id: 'AXJMbIl9PAOIsUIE3gsw',
key: 'new_security_hotspots',
qualitative: true,
hidden: false,
},
+ new_software_quality_security_issues: {
+ id: 'ecf1983d-ea7e-4df6-b377-d16f4a5a59e6',
+ key: 'new_software_quality_security_issues',
+ type: 'INT',
+ name: 'New Security Issues',
+ description: 'New Security Issues',
+ domain: 'Security',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_security_issues: {
id: '6887ef7d-ee21-449c-b1ff-f3f7930ba27f',
key: 'new_security_issues',
qualitative: false,
hidden: false,
},
+ software_quality_reliability_issues: {
+ id: '765f3905-47df-4d9c-b568-9184f341a737',
+ key: 'software_quality_reliability_issues',
+ type: 'INT',
+ name: 'Reliability Issues',
+ description: 'Reliability Issues',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: false,
+ hidden: false,
+ },
reliability_rating: {
id: 'AXJMbIl_PAOIsUIE3guP',
key: 'reliability_rating',
qualitative: true,
hidden: false,
},
+ software_quality_reliability_rating: {
+ id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78',
+ key: 'software_quality_reliability_rating',
+ type: 'RATING',
+ name: 'Reliability Rating',
+ description: 'Reliability rating',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
reliability_rating_distribution: {
id: 'AX3sJDjuJHBehddvNyhO',
key: 'reliability_rating_distribution',
qualitative: true,
hidden: false,
},
+ new_software_quality_reliability_rating: {
+ id: 'ab82dcac-cf81-4780-965d-1384ce9e8983',
+ key: 'new_software_quality_reliability_rating',
+ type: 'RATING',
+ name: 'Reliability Rating on New Code',
+ description: 'Reliability rating on new code',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
reliability_remediation_effort: {
id: 'AXJMbIl_PAOIsUIE3guN',
key: 'reliability_remediation_effort',
qualitative: true,
hidden: false,
},
+ software_quality_reliability_remediation_effort: {
+ id: 'f2094b93-e08c-4350-ad8f-f265974278a8',
+ key: 'software_quality_reliability_remediation_effort',
+ type: 'WORK_DUR',
+ name: 'Reliability Remediation Effort',
+ description: 'Reliability remediation effort',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
+ new_software_quality_reliability_remediation_effort: {
+ id: '45f9a292-5f6e-459e-8d81-134d5aaedef9',
+ key: 'new_software_quality_reliability_remediation_effort',
+ type: 'WORK_DUR',
+ name: 'Reliability Remediation Effort on New Code',
+ description: 'Reliability remediation effort on new code',
+ domain: 'Reliability',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_reliability_remediation_effort: {
id: 'AXJMbIl_PAOIsUIE3guO',
key: 'new_reliability_remediation_effort',
qualitative: false,
hidden: false,
},
+ software_quality_security_issues: {
+ id: '7133e418-aadb-4cac-b31f-b13bf036a7ff',
+ key: 'software_quality_security_issues',
+ type: 'INT',
+ name: 'Security Issues',
+ description: 'Security Issues',
+ domain: 'Security',
+ direction: -1,
+ qualitative: false,
+ hidden: false,
+ },
security_rating: {
id: 'AXJMbIl_PAOIsUIE3guS',
key: 'security_rating',
qualitative: true,
hidden: false,
},
+ software_quality_security_rating: {
+ id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429',
+ key: 'software_quality_security_rating',
+ type: 'RATING',
+ name: 'Security Rating',
+ description: 'Security rating',
+ domain: 'Security',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
security_rating_distribution: {
id: 'AX3sJDjuJHBehddvNyhP',
key: 'security_rating_distribution',
qualitative: true,
hidden: true,
},
+ new_software_quality_security_rating: {
+ id: '228b9a04-09a2-418e-9ea4-3584a57a95ba',
+ key: 'new_software_quality_security_rating',
+ type: 'RATING',
+ name: 'Security Rating on New Code',
+ description: 'Security rating on new code',
+ domain: 'Security',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
new_security_rating: {
id: 'AXJMbImPPAOIsUIE3guT',
key: 'new_security_rating',
qualitative: true,
hidden: false,
},
+ software_quality_security_remediation_effort: {
+ id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71',
+ key: 'software_quality_security_remediation_effort',
+ type: 'WORK_DUR',
+ name: 'Security Remediation Effort',
+ description: 'Security remediation effort',
+ domain: 'Security',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
security_remediation_effort: {
id: 'AXJMbIl_PAOIsUIE3guG',
key: 'security_remediation_effort',
qualitative: true,
hidden: false,
},
+ new_software_quality_security_remediation_effort: {
+ id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4',
+ key: 'new_software_quality_security_remediation_effort',
+ type: 'WORK_DUR',
+ name: 'Security Remediation Effort on New Code',
+ description: 'Security remediation effort on new code',
+ domain: 'Security',
+ direction: -1,
+ qualitative: true,
+ hidden: false,
+ },
security_review_rating: {
id: 'AXJMbIl9PAOIsUIE3gsx',
key: 'security_review_rating',
qualitative: true,
hidden: false,
},
- effort_to_reach_software_quality_maintainability_rating_a: {
- id: '0f195cdf-5d79-4be0-90e4-c6e0afb58551',
- key: 'effort_to_reach_software_quality_maintainability_rating_a',
- type: 'WORK_DUR',
- name: 'Software Quality Effort to Reach Maintainability Rating A',
- description: 'Software quality effort to reach maintainability rating A',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_maintainability_rating: {
- id: '9fc76baf-f660-4f65-a271-b2ae7f849239',
- key: 'software_quality_maintainability_rating',
- type: 'RATING',
- name: 'Software Quality Maintainability Rating',
- description: 'Software quality maintainability rating',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
software_quality_maintainability_rating_distribution: {
id: 'b39b797b-216d-4800-810e-2277012ee096',
key: 'software_quality_maintainability_rating_distribution',
qualitative: false,
hidden: true,
},
- new_software_quality_maintainability_rating: {
- id: 'c5d12cc4-e712-4701-a395-c9113ce13c3e',
- key: 'new_software_quality_maintainability_rating',
- type: 'RATING',
- name: 'Software Quality Maintainability Rating on New Code',
- description: 'Software quality maintainability rating on new code',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_maintainability_remediation_effort: {
- id: '24edda40-db1c-4acd-9c9b-66d5bcca8486',
- key: 'software_quality_maintainability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Software Quality Maintainability Remediation Effort',
- description:
- 'Software quality total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_maintainability_remediation_effort: {
- id: 'bf182476-9397-4471-812d-7e40568ef1b0',
- key: 'new_software_quality_maintainability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Software Quality Maintainability Remediation Effort on new code',
- description:
- 'Software quality total effort (in minutes) to fix all the maintainability issues on new code on the component and therefore to comply to all the requirements.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_releasability_rating: {
- id: '1fb38855-84b8-41b2-88a0-50c3dceda102',
- key: 'software_quality_releasability_rating',
- type: 'RATING',
- name: 'Software Quality Releasability rating',
- domain: 'Releasability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_releasability_rating_distribution: {
- id: 'a34a08a2-29b5-4efb-bd2a-eebe3dc10dab',
- key: 'software_quality_releasability_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Releasability Rating Distribution',
- description: 'Software Quality Releasability rating distribution',
- domain: 'Releasability',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- software_quality_reliability_rating: {
- id: '6548ffa4-8a5e-4445-a28d-e2fd9fdbba78',
- key: 'software_quality_reliability_rating',
- type: 'RATING',
- name: 'Software Quality Reliability Rating',
- description: 'Software quality reliability rating',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
software_quality_reliability_rating_distribution: {
id: '571de2d7-d1ef-460b-8f99-e29e0aa6218c',
key: 'software_quality_reliability_rating_distribution',
qualitative: false,
hidden: true,
},
- new_software_quality_reliability_rating: {
- id: 'ab82dcac-cf81-4780-965d-1384ce9e8983',
- key: 'new_software_quality_reliability_rating',
- type: 'RATING',
- name: 'Software Quality Reliability Rating on New Code',
- description: 'Software quality reliability rating on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_reliability_remediation_effort: {
- id: 'f2094b93-e08c-4350-ad8f-f265974278a8',
- key: 'software_quality_reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Software Quality Reliability Remediation Effort',
- description: 'Software quality reliability remediation effort',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- new_software_quality_reliability_remediation_effort: {
- id: '45f9a292-5f6e-459e-8d81-134d5aaedef9',
- key: 'new_software_quality_reliability_remediation_effort',
- type: 'WORK_DUR',
- name: 'Software Quality Reliability Remediation Effort on New Code',
- description: 'Software quality reliability remediation effort on new code',
- domain: 'Reliability',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_security_rating: {
- id: 'db22dacd-a3fd-41d2-8617-0cb7cfc86429',
- key: 'software_quality_security_rating',
- type: 'RATING',
- name: 'Software Quality Security Rating',
- description: 'Software quality security rating',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
software_quality_security_rating_distribution: {
id: 'f9a76abe-7663-47b3-a27c-1dea7e6b4861',
key: 'software_quality_security_rating_distribution',
qualitative: false,
hidden: true,
},
- new_software_quality_security_rating: {
- id: '228b9a04-09a2-418e-9ea4-3584a57a95ba',
- key: 'new_software_quality_security_rating',
- type: 'RATING',
- name: 'Software Quality Security Rating on New Code',
- description: 'Software quality security rating on new code',
- domain: 'Security',
+ statements: {
+ id: 'AXJMbImPPAOIsUIE3gum',
+ key: 'statements',
+ type: 'INT',
+ name: 'Statements',
+ description: 'Number of statements',
+ domain: 'Size',
direction: -1,
- qualitative: true,
+ qualitative: false,
hidden: false,
},
- software_quality_security_remediation_effort: {
- id: '43652a84-3ca7-4506-9c09-00ea2b6c6e71',
- key: 'software_quality_security_remediation_effort',
+ software_quality_maintainability_remediation_effort: {
+ id: '24edda40-db1c-4acd-9c9b-66d5bcca8486',
+ key: 'software_quality_maintainability_remediation_effort',
type: 'WORK_DUR',
- name: 'Software Quality Security Remediation Effort',
- description: 'Software quality security remediation effort',
- domain: 'Security',
+ name: 'Technical Debt',
+ description:
+ 'Total effort (in minutes) to fix all the maintainability issues on the component and therefore to comply to all the requirements.',
+ domain: 'Maintainability',
direction: -1,
qualitative: true,
hidden: false,
},
- new_software_quality_security_remediation_effort: {
- id: 'd5d0020a-419c-4387-b00f-523ad8a6a3e4',
- key: 'new_software_quality_security_remediation_effort',
+ sqale_index: {
+ id: 'AXJMbIl_PAOIsUIE3guD',
+ key: 'sqale_index',
type: 'WORK_DUR',
- name: 'Software Quality Security Remediation Effort on New Code',
- description: 'Software quality security remediation effort on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_security_review_rating: {
- id: '6e09531b-dee8-4c23-9a76-dc335cf79019',
- key: 'software_quality_security_review_rating',
- type: 'RATING',
- name: 'Software Quality Security Review Rating',
- description: 'Software quality security review rating',
- domain: 'SecurityReview',
- direction: -1,
- qualitative: true,
- hidden: false,
- },
- software_quality_security_review_rating_distribution: {
- id: '3b9d046c-a319-4cbf-99c4-15c206e71401',
- key: 'software_quality_security_review_rating_distribution',
- type: 'DATA',
- name: 'software Quality Security Review Rating Distribution',
- description: 'Software Quality Security review rating distribution',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- new_software_quality_security_review_rating_distribution: {
- id: 'b6565b9b-3676-405f-8149-a37cb0bd78b9',
- key: 'new_software_quality_security_review_rating_distribution',
- type: 'DATA',
- name: 'Software Quality Security Review Rating Distribution on New Code',
- description: 'Software Quality Security review rating distribution on new code',
- domain: 'Security',
- direction: -1,
- qualitative: true,
- hidden: true,
- },
- software_quality_security_review_rating_effort: {
- id: '8d6d023e-6764-42ee-9fb7-bc1f17bda205',
- key: 'software_quality_security_review_rating_effort',
- type: 'DATA',
- name: 'Software Quality Security Review Rating Effort',
- domain: 'Security',
- direction: 0,
- qualitative: false,
- hidden: true,
- },
- new_software_quality_security_review_rating: {
- id: '4d4b1d18-da7e-403c-a3f0-99951c58b050',
- key: 'new_software_quality_security_review_rating',
- type: 'RATING',
- name: 'Software Quality Security Review Rating on New Code',
- description: 'Software quality security review rating on new code',
- domain: 'SecurityReview',
+ name: 'Technical Debt',
+ description:
+ 'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.',
+ domain: 'Maintainability',
direction: -1,
qualitative: true,
hidden: false,
id: '8a7a5279-9dfe-4fdf-9886-9203ae50be5c',
key: 'software_quality_maintainability_debt_ratio',
type: 'PERCENT',
- name: 'Software Quality Technical Debt Ratio',
+ name: 'Technical Debt Ratio',
description:
- 'Software quality ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
+ 'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
domain: 'Maintainability',
direction: -1,
qualitative: true,
hidden: false,
decimalScale: 1,
},
- new_software_quality_maintainability_debt_ratio: {
- id: '23330467-a21e-4254-a76a-2eb99aab6f0f',
- key: 'new_software_quality_maintainability_debt_ratio',
+ sqale_debt_ratio: {
+ id: 'AXJMbIl_PAOIsUIE3guK',
+ key: 'sqale_debt_ratio',
type: 'PERCENT',
- name: 'Software Quality Technical Debt Ratio on New Code',
- description: 'Software quality technical debt ratio software quality of new/changed code.',
- domain: 'Maintainability',
- direction: -1,
- qualitative: true,
- hidden: false,
- decimalScale: 1,
- },
- statements: {
- id: 'AXJMbImPPAOIsUIE3gum',
- key: 'statements',
- type: 'INT',
- name: 'Statements',
- description: 'Number of statements',
- domain: 'Size',
- direction: -1,
- qualitative: false,
- hidden: false,
- },
- sqale_index: {
- id: 'AXJMbIl_PAOIsUIE3guD',
- key: 'sqale_index',
- type: 'WORK_DUR',
- name: 'Technical Debt',
+ name: 'Technical Debt Ratio',
description:
- 'Total effort (in minutes) to fix all the issues on the component and therefore to comply to all the requirements.',
+ 'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
domain: 'Maintainability',
direction: -1,
qualitative: true,
hidden: false,
+ decimalScale: 1,
},
- sqale_debt_ratio: {
- id: 'AXJMbIl_PAOIsUIE3guK',
- key: 'sqale_debt_ratio',
+ new_software_quality_maintainability_debt_ratio: {
+ id: '23330467-a21e-4254-a76a-2eb99aab6f0f',
+ key: 'new_software_quality_maintainability_debt_ratio',
type: 'PERCENT',
- name: 'Technical Debt Ratio',
- description:
- 'Ratio of the actual technical debt compared to the estimated cost to develop the whole source code from scratch',
+ name: 'Technical Debt Ratio on New Code',
+ description: 'Technical Debt Ratio on New Code',
domain: 'Maintainability',
direction: -1,
qualitative: true,
});
}
-export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric?: boolean) {
+export function useUpdateOrDeleteConditionsMutation(gateName: string, isSingleMetric = false) {
const queryClient = useQueryClient();
const intl = useIntl();
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.mqr_mode_update.single_metric.tooltip.message=Update {metric} metric to {mode}
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.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.metric.standard_mode_short=Standard Experience
+quality_gates.metric.standard_mode_long=Standard Experience Metric
+quality_gates.metric.mqr_mode_short=MQR Mode
+quality_gates.metric.mqr_mode_long=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
+quality_gates.mode_banner.title=This quality gate is using conditions with metrics that belong to the {mode}
+quality_gates.mode_banner.description=This instance is currently in the {link}. We recommend you update the metrics of your quality gate conditions to ensure accurate categorization and ranking of your issues in this mode. Conditions that use {otherMode} metrics can’t be edited until they are updated.
+quality_gates.mode_banner.button=Review and update metrics
#------------------------------------------------------------------------------