diff options
author | Viktor Vorona <viktor.vorona@sonarsource.com> | 2024-05-29 17:55:27 +0200 |
---|---|---|
committer | sonartech <sonartech@sonarsource.com> | 2024-06-03 20:02:58 +0000 |
commit | 411f1d1ae8b2c7128cabfa7a791bc76f5b2f944d (patch) | |
tree | a8078395bc1f885b699c0afedaf0f7664525ffa5 /server | |
parent | 1d4707b86a5a03f3895cbff760fc9824655d9da2 (diff) | |
download | sonarqube-411f1d1ae8b2c7128cabfa7a791bc76f5b2f944d.tar.gz sonarqube-411f1d1ae8b2c7128cabfa7a791bc76f5b2f944d.zip |
SONAR-22224 Disable editing on new metric
Diffstat (limited to 'server')
7 files changed, 90 insertions, 25 deletions
diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionModal.tsx index f01e9c1abda..d17cb066a2a 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionModal.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/AddConditionModal.tsx @@ -23,8 +23,9 @@ import * as React from 'react'; import { translate } from '../../../helpers/l10n'; import { isDiffMetric } from '../../../helpers/measures'; import { useCreateConditionMutation } from '../../../queries/quality-gates'; +import { MetricKey } from '../../../sonar-aligned/types/metrics'; import { Condition, Metric, QualityGate } from '../../../types/types'; -import { getPossibleOperators } from '../utils'; +import { getPossibleOperators, isNonEditableMetric } from '../utils'; import ConditionOperator from './ConditionOperator'; import MetricSelect from './MetricSelect'; import ThresholdInput from './ThresholdInput'; @@ -79,7 +80,7 @@ export default function AddConditionModal({ metrics, onClose, qualityGate }: Rea const handleMetricChange = (metric: Metric) => { setSelectedMetric(metric); setSelectedOperator(undefined); - setErrorThreshold(''); + setErrorThreshold(metric.key === MetricKey.prioritized_rule_issues ? '0' : ''); }; const handleOperatorChange = (op: string) => { @@ -137,6 +138,7 @@ export default function AddConditionModal({ metrics, onClose, qualityGate }: Rea > <ThresholdInput metric={selectedMetric} + disabled={isNonEditableMetric(selectedMetric.key as MetricKey)} name="error" onChange={handleErrorChange} value={errorThreshold} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx index e15de9c0759..d225dc4c5f0 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Condition.tsx @@ -35,8 +35,13 @@ 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 { MetricKey } from '../../../sonar-aligned/types/metrics'; import { CaycStatus, Condition as ConditionType, Metric, QualityGate } from '../../../types/types'; -import { getLocalizedMetricNameNoDiffMetric, isConditionWithFixedValue } from '../utils'; +import { + getLocalizedMetricNameNoDiffMetric, + isConditionWithFixedValue, + isNonEditableMetric, +} from '../utils'; import ConditionValue from './ConditionValue'; import EditConditionModal from './EditConditionModal'; @@ -109,27 +114,31 @@ export default function ConditionComponent({ <> {(!isCaycCompliantAndOverCompliant || !isConditionWithFixedValue(condition) || - (isCaycCompliantAndOverCompliant && showEdit)) && ( - <> - <InteractiveIcon - Icon={PencilIcon} - aria-label={translateWithParameters('quality_gates.condition.edit', metric.name)} - data-test="quality-gates__condition-update" - onClick={handleOpenUpdate} - className="sw-mr-4" - size="small" - /> - {modal && ( - <EditConditionModal - condition={condition} - header={translate('quality_gates.update_condition')} - metric={metric} - onClose={handleUpdateClose} - qualityGate={qualityGate} + (isCaycCompliantAndOverCompliant && showEdit)) && + !isNonEditableMetric(condition.metric as MetricKey) && ( + <> + <InteractiveIcon + Icon={PencilIcon} + aria-label={translateWithParameters( + 'quality_gates.condition.edit', + metric.name, + )} + data-test="quality-gates__condition-update" + onClick={handleOpenUpdate} + className="sw-mr-4" + size="small" /> - )} - </> - )} + {modal && ( + <EditConditionModal + condition={condition} + header={translate('quality_gates.update_condition')} + metric={metric} + onClose={handleUpdateClose} + qualityGate={qualityGate} + /> + )} + </> + )} {(!isCaycCompliantAndOverCompliant || !condition.isCaycCondition || (isCaycCompliantAndOverCompliant && showEdit)) && ( diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.tsx index b832428a495..de3c5df6505 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ThresholdInput.tsx @@ -25,6 +25,7 @@ import { Metric } from '../../../types/types'; interface Props { name: string; value: string; + disabled?: boolean; metric: Metric; onChange: (value: string) => void; } @@ -67,7 +68,7 @@ export default class ThresholdInput extends React.PureComponent<Props> { } render() { - const { name, value, metric } = this.props; + const { name, value, disabled, metric } = this.props; if (metric.type === 'RATING') { return this.renderRatingInput(); @@ -77,6 +78,7 @@ export default class ThresholdInput extends React.PureComponent<Props> { <InputField size="small" data-type={metric.type} + disabled={disabled} id="condition-threshold" name={name} onChange={this.handleChange} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx index 31b58311c5d..d3230d5eb5b 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/__tests__/QualityGate-it.tsx @@ -20,7 +20,7 @@ import { screen, waitFor, within } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import selectEvent from 'react-select-event'; -import { byRole, byTestId } from '~sonar-aligned/helpers/testSelector'; +import { byLabelText, byRole, byTestId } from '~sonar-aligned/helpers/testSelector'; import { QualityGatesServiceMock } from '../../../../api/mocks/QualityGatesServiceMock'; import UsersServiceMock from '../../../../api/mocks/UsersServiceMock'; import { searchProjects, searchUsers } from '../../../../api/quality-gates'; @@ -556,6 +556,41 @@ it('should not display CaYC condition simplification tour for users who dismisse expect(byRole('alertdialog').query()).not.toBeInTheDocument(); }); +it('should not allow to change value of prioritized_rule_issues', async () => { + const user = userEvent.setup(); + qualityGateHandler.setIsAdmin(true); + renderQualityGateApp(); + + await user.click(await screen.findByText('SonarSource way - CFamily')); + + await user.click(await screen.findByText('quality_gates.add_condition')); + + const dialog = byRole('dialog'); + + await user.click(dialog.byRole('radio', { name: 'quality_gates.conditions.overall_code' }).get()); + await selectEvent.select(dialog.byRole('combobox').get(), ['Issues from prioritized rules']); + + expect(dialog.byRole('textbox', { name: 'quality_gates.conditions.value' }).get()).toBeDisabled(); + expect(dialog.byRole('textbox', { name: 'quality_gates.conditions.value' }).get()).toHaveValue( + '0', + ); + + await user.click(dialog.byRole('button', { name: 'quality_gates.add_condition' }).get()); + + const overallConditions = byTestId('quality-gates__conditions-overall'); + + expect( + await overallConditions.byRole('cell', { name: 'Issues from prioritized rules' }).find(), + ).toBeInTheDocument(); + + expect( + byLabelText('quality_gates.condition.edit.Issues from prioritized rules').query(), + ).not.toBeInTheDocument(); + expect( + byLabelText('quality_gates.condition.delete.Issues from prioritized rules').get(), + ).toBeInTheDocument(); +}); + describe('The Project section', () => { it('should render list of projects correctly in different tabs', async () => { const user = userEvent.setup(); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts b/server/sonar-web/src/main/js/apps/quality-gates/utils.ts index cb37ff4039a..ab487e58aa5 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/utils.ts +++ b/server/sonar-web/src/main/js/apps/quality-gates/utils.ts @@ -141,11 +141,16 @@ const CAYC_CONDITIONS_WITH_FIXED_VALUE: AllCaycMetricKeys[] = [ MetricKey.new_security_rating, MetricKey.new_maintainability_rating, ]; +const NON_EDITABLE_CONDITIONS: MetricKey[] = [MetricKey.prioritized_rule_issues]; export function isConditionWithFixedValue(condition: Condition) { return CAYC_CONDITIONS_WITH_FIXED_VALUE.includes(condition.metric as OptimizedCaycMetricKeys); } +export function isNonEditableMetric(metricKey: MetricKey) { + return NON_EDITABLE_CONDITIONS.includes(metricKey); +} + export function getCaycConditionMetadata(condition: Condition) { const foundCondition = OPTIMIZED_CAYC_CONDITIONS[condition.metric as OptimizedCaycMetricKeys]; return { diff --git a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts index 60febc0fb71..d191dd1e76b 100644 --- a/server/sonar-web/src/main/js/helpers/mocks/metrics.ts +++ b/server/sonar-web/src/main/js/helpers/mocks/metrics.ts @@ -17,6 +17,7 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ +import { MetricKey } from '../../sonar-aligned/types/metrics'; import { Dict, Metric } from '../../types/types'; export const DEFAULT_METRICS: Dict<Metric> = { @@ -830,6 +831,16 @@ export const DEFAULT_METRICS: Dict<Metric> = { qualitative: false, hidden: true, }, + [MetricKey.prioritized_rule_issues]: { + key: 'prioritized_rule_issues', + type: 'INT', + name: 'Issues from prioritized rules', + description: 'Count of issues that have a flag Prioritized Rule.', + domain: 'Issues', + direction: -1, + qualitative: true, + hidden: false, + }, projects: { key: 'projects', type: 'INT', diff --git a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts b/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts index a98e6d016e2..53aed15b4fb 100644 --- a/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts +++ b/server/sonar-web/src/main/js/sonar-aligned/types/metrics.ts @@ -122,6 +122,7 @@ export enum MetricKey { new_violations_rating = 'new_violations_rating', new_vulnerabilities = 'new_vulnerabilities', open_issues = 'open_issues', + prioritized_rule_issues = 'prioritized_rule_issues', projects = 'projects', public_api = 'public_api', public_documented_api_density = 'public_documented_api_density', |