From 98ec043c4f45a6168735b694351b2e6c86f5239f Mon Sep 17 00:00:00 2001 From: Viktor Vorona Date: Mon, 7 Oct 2024 14:36:18 +0200 Subject: [PATCH] SONAR-23263 Redesign Quality Profile select in activation modal --- .../__tests__/CodingRuleDetails-it.ts | 28 ++--- .../components/ActivationFormModal.tsx | 106 ++++++++++-------- .../main/js/apps/coding-rules/utils-tests.tsx | 2 +- .../resources/org/sonar/l10n/core.properties | 4 +- 4 files changed, 80 insertions(+), 60 deletions(-) diff --git a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts index 805a4fcb5c7..a5010470c86 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts +++ b/server/sonar-web/src/main/js/apps/coding-rules/__tests__/CodingRuleDetails-it.ts @@ -177,6 +177,15 @@ it('can activate/change/deactivate rule in quality profile', async () => { renderCodingRulesApp(mockLoggedInUser(), 'coding_rules?open=rule1', [Feature.PrioritizedRules]); expect(await ui.qpLink('QP Foo').find()).toBeInTheDocument(); + // Activate profile with inherited ones java rule + await user.click(ui.activateButton.get()); + await user.click(ui.qualityProfileSelect.get()); + await user.click(byRole('option', { name: 'QP FooBarBaz' }).get()); + await user.type(ui.paramInput('1').get(), 'paramInput'); + await user.click(ui.activateButton.get(ui.activateQPDialog.get())); + expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument(); + expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument(); + // Activate rule in quality profile expect(ui.prioritizedRuleCell.query()).not.toBeInTheDocument(); await user.click(ui.activateButton.get()); @@ -194,13 +203,6 @@ it('can activate/change/deactivate rule in quality profile', async () => { 'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.LOW', ); - // Activate last java rule - await user.click(ui.activateButton.get()); - await user.type(ui.paramInput('1').get(), 'paramInput'); - await user.click(ui.activateButton.get(ui.activateQPDialog.get())); - expect(ui.qpLink('QP FooBarBaz').get()).toBeInTheDocument(); - expect(ui.qpLink('QP FooBaz').get()).toBeInTheDocument(); - // Rule is activated in all quality profiles - show notification in dialog await user.click(ui.activateButton.get(screen.getByRole('main'))); expect(ui.activaInAllQPs.get()).toBeInTheDocument(); @@ -215,10 +217,10 @@ it('can activate/change/deactivate rule in quality profile', async () => { await user.click(ui.newSeveritySelect(SoftwareQuality.Maintainability).get()); await user.click(byRole('option', { name: 'severity_impact.BLOCKER' }).get()); await user.click(ui.saveButton.get(ui.changeQPDialog.get())); - expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz'); - expect(ui.qualityProfileRow.getAt(5)).toHaveTextContent('New'); + expect(await ui.qualityProfileRow.findAt(4)).toHaveTextContent('QP FooBaz'); + expect(ui.qualityProfileRow.getAt(4)).toHaveTextContent('New'); await expect( - ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(5)), + ui.newSeverityCustomizedCell.get(ui.qualityProfileRow.getAt(4)), ).toHaveATooltipWithContent( 'coding_rules.impact_customized.detailsoftware_quality.MAINTAINABILITYseverity_impact.MEDIUMseverity_impact.BLOCKER', ); @@ -226,9 +228,9 @@ it('can activate/change/deactivate rule in quality profile', async () => { // Revert rule details in quality profile await user.click(ui.revertToParentDefinitionButton.get()); await user.click(ui.yesButton.get()); - expect(await ui.qualityProfileRow.findAt(5)).toHaveTextContent('QP FooBaz'); - expect(await ui.qualityProfileRow.findAt(5)).not.toHaveTextContent('New'); - expect(ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(5))).not.toBeInTheDocument(); + expect(await ui.qualityProfileRow.findAt(4)).toHaveTextContent('QP FooBaz'); + expect(await ui.qualityProfileRow.findAt(4)).not.toHaveTextContent('New'); + expect(ui.newSeverityCustomizedCell.query(ui.qualityProfileRow.getAt(4))).not.toBeInTheDocument(); // Deactivate rule in quality profile await user.click(ui.deactivateInQPButton('QP FooBar').get()); diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx index a06bb85d86d..6c439093d7c 100644 --- a/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ActivationFormModal.tsx @@ -18,14 +18,12 @@ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ -import { Button, ButtonVariety, Checkbox, Modal, Text } from '@sonarsource/echoes-react'; +import { Button, ButtonVariety, Checkbox, Modal, Select, Text } from '@sonarsource/echoes-react'; import { FlagMessage, FormField, InputField, - InputSelect, InputTextArea, - LabelValueSelectOption, Note, SafeHTMLInjection, SanitizeLevel, @@ -74,9 +72,7 @@ export default function ActivationFormModal(props: Readonly) { const [changedPrioritizedRule, setChangedPrioritizedRule] = React.useState( undefined, ); - const [changedProfile, setChangedProfile] = React.useState( - undefined, - ); + const [changedProfile, setChangedProfile] = React.useState(undefined); const [changedParams, setChangedParams] = React.useState | undefined>( undefined, ); @@ -94,7 +90,7 @@ export default function ActivationFormModal(props: Readonly) { const prioritizedRule = changedPrioritizedRule ?? (activation ? activation.prioritizedRule : false); - const profile = changedProfile ?? profilesWithDepth[0]; + const profile = profiles.find((p) => p.key === changedProfile) ?? profilesWithDepth[0]; const params = changedParams ?? getRuleParams({ activation, rule }); const severity = changedSeverity ?? ((activation ? activation.severity : rule.severity) as IssueSeverity); @@ -105,7 +101,11 @@ export default function ActivationFormModal(props: Readonly) { .map((impact) => [impact.softwareQuality, impact.severity] as const) ?? []), ...changedImpactSeveritiesMap, ]); - const profileOptions = profilesWithDepth.map((p) => ({ label: p.name, value: p })); + const profileOptions = profilesWithDepth.map((p) => ({ + label: p.name, + value: p.key, + prefix: ' '.repeat(p.depth), + })); const isCustomRule = !!(rule as RuleDetails).templateKey; const activeInAllProfiles = profilesWithDepth.length <= 0; const isUpdateMode = !!activation; @@ -167,48 +167,56 @@ export default function ActivationFormModal(props: Readonly) { } content={
+ + {rule.name}, + }} + /> + + {!isUpdateMode && activeInAllProfiles && ( - + {intl.formatMessage({ id: 'coding_rules.active_in_all_profiles' })} )} - - ) => { - setChangedProfile(value); - }} - getOptionLabel={({ value }: LabelValueSelectOption) => - ' '.repeat(value.depth) + value.name - } - options={profileOptions} - value={profileOptions.find(({ value }) => value.key === profile?.key)} - /> - + {profilesWithDepth.length >= MIN_PROFILES_TO_ENABLE_SELECT ? ( + +