From 2f6d8003fcc62e3fcf2e5db3157e93425a5c16f8 Mon Sep 17 00:00:00 2001 From: Rajashekar-codescan Date: Thu, 14 May 2026 18:27:09 +0530 Subject: [PATCH] CD-8721 Added Ui changes for custom rules with Ai feature --- server/sonar-web/src/main/js/@types/svg.d.ts | 24 + .../ai-custom-rules/AIRuleFormModal.css | 69 ++ .../ai-custom-rules/AIRuleFormModal.tsx | 259 ++++++++ .../ai-custom-rules/AIRuleWizard.css | 277 ++++++++ .../ai-custom-rules/AIRuleWizard.tsx | 308 +++++++++ .../CreateRuleSelectionModal.css | 219 +++++++ .../CreateRuleSelectionModal.tsx | 126 ++++ .../components/ai-custom-rules/DefineStep.css | 432 +++++++++++++ .../components/ai-custom-rules/DefineStep.tsx | 324 ++++++++++ .../ai-custom-rules/GenerateStep.css | 252 ++++++++ .../ai-custom-rules/GenerateStep.tsx | 173 +++++ .../GenerationProgressModal.css | 144 +++++ .../GenerationProgressModal.tsx | 163 +++++ .../ai-custom-rules/ReviewActivateScreen.css | 234 +++++++ .../ai-custom-rules/ReviewActivateScreen.tsx | 173 +++++ .../components/ai-custom-rules/ReviewStep.css | 591 ++++++++++++++++++ .../components/ai-custom-rules/ReviewStep.tsx | 288 +++++++++ .../ai-custom-rules/aiRuleService.ts | 40 ++ .../ai-custom-rules/icons/AlertCircle.svg | 12 + .../ai-custom-rules/icons/Check-generated.svg | 3 + .../ai-custom-rules/icons/Check.svg | 3 + .../ai-custom-rules/icons/CheckLoading.svg | 3 + .../ai-custom-rules/icons/ChevronLeft.svg | 3 + .../ai-custom-rules/icons/ChevronRight.svg | 3 + .../ai-custom-rules/icons/Code2.svg | 12 + .../components/ai-custom-rules/icons/Copy.svg | 11 + .../icons/Icon-aican-make-mistakes.svg | 14 + .../ai-custom-rules/icons/Icon-orange.svg | 4 + .../components/ai-custom-rules/icons/Info.svg | 12 + .../ai-custom-rules/icons/Loader-anim.svg | 6 + .../ai-custom-rules/icons/Pencil.svg | 11 + .../ai-custom-rules/icons/RotateCcw.svg | 4 + .../ai-custom-rules/icons/Sparkles-1.svg | 14 + .../ai-custom-rules/icons/Sparkles-2.svg | 7 + .../ai-custom-rules/icons/Sparkles-3.svg | 7 + .../ai-custom-rules/icons/Sparkles-4.svg | 7 + .../ai-custom-rules/icons/Sparkles-5.svg | 14 + .../ai-custom-rules/icons/Sparkles-6.svg | 14 + .../icons/Sparkles-loading-page.svg | 7 + .../ai-custom-rules/icons/Sparkles.svg | 14 + .../ai-custom-rules/icons/X-loading-page.svg | 4 + .../components/ai-custom-rules/icons/X.svg | 4 + .../ai-custom-rules/icons/copied.svg | 11 + .../ai-custom-rules/icons/motion.div.svg | 3 + .../icons/severity-blocker.svg | 4 + .../icons/severity-critical.svg | 4 + .../ai-custom-rules/icons/severity-info.svg | 5 + .../ai-custom-rules/icons/severity-major.svg | 4 + .../ai-custom-rules/icons/severity-minor.svg | 4 + 49 files changed, 4324 insertions(+) create mode 100644 server/sonar-web/src/main/js/@types/svg.d.ts create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleWizard.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleWizard.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/CreateRuleSelectionModal.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/CreateRuleSelectionModal.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/DefineStep.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/DefineStep.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/GenerateStep.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/GenerateStep.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/GenerationProgressModal.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/GenerationProgressModal.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/ReviewActivateScreen.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/ReviewActivateScreen.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/ReviewStep.css create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/ReviewStep.tsx create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/aiRuleService.ts create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/AlertCircle.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Check-generated.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Check.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/CheckLoading.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/ChevronLeft.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/ChevronRight.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Code2.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Copy.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Icon-aican-make-mistakes.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Icon-orange.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Info.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Loader-anim.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Pencil.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/RotateCcw.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-1.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-2.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-3.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-4.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-5.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-6.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles-loading-page.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/Sparkles.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/X-loading-page.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/X.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/copied.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/motion.div.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/severity-blocker.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/severity-critical.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/severity-info.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/severity-major.svg create mode 100644 server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/icons/severity-minor.svg diff --git a/server/sonar-web/src/main/js/@types/svg.d.ts b/server/sonar-web/src/main/js/@types/svg.d.ts new file mode 100644 index 000000000000..53cd43019be8 --- /dev/null +++ b/server/sonar-web/src/main/js/@types/svg.d.ts @@ -0,0 +1,24 @@ +/* + * 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. + */ + +declare module '*.svg' { + const content: string; + export default content; +} diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.css b/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.css new file mode 100644 index 000000000000..56a5d0713989 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.css @@ -0,0 +1,69 @@ +/* + * 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. + */ +.ai-rule-form-body { + max-width: 900px; +} + +.ai-rule-form-alert { + line-height: 1.6; +} + +.ai-rule-form-alert p { + margin: 8px 0 0 0; + color: #666; +} + +.form-field-error { + color: #d4333f; + font-size: 12px; + margin-top: 4px; +} + +.ai-examples-section { + background: #f5f5f5; + padding: 16px; + border-radius: 4px; + margin-top: 16px; +} + +.ai-examples-list { + margin: 8px 0 0 20px; + padding: 0; + list-style-type: none; +} + +.ai-examples-list li { + margin-bottom: 8px; + line-height: 1.6; + color: #666; +} + +.ai-examples-list li:before { + content: "•"; + margin-right: 8px; + color: #4b9fd5; +} + +.ai-form-actions { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; +} diff --git a/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.tsx b/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.tsx new file mode 100644 index 000000000000..0a0429e2e9a6 --- /dev/null +++ b/server/sonar-web/src/main/js/apps/coding-rules/components/ai-custom-rules/AIRuleFormModal.tsx @@ -0,0 +1,259 @@ +/* + * 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, Modal, ModalSize, Select, Text } from '@sonarsource/echoes-react'; +import { SyntheticEvent, useState } from 'react'; +import { FormField, InputField, InputTextArea, LabelValueSelectOption } from '~design-system'; +import { RULE_TYPES } from '../../../../helpers/constants'; +import { translate } from '../../../../helpers/l10n'; +import { latinize } from '../../../../helpers/strings'; +import { SeveritySelect } from '../SeveritySelect'; +import SparklesSvg from './icons/Sparkles-2.svg'; + +interface Props { + isOpen: boolean; + onClose: () => void; + onSubmit: (values: AIRuleFormValues) => void; + organization: string; +} + +export interface AIRuleFormValues { + ruleName: string; + ruleKey: string; + ruleType: string; + severity: string; + message: string; + ruleDescription: string; +} + +const MAX_CHAR_COUNT = 5000; +const MIN_CHAR_COUNT = 20; + +const EXAMPLE_DESCRIPTIONS = [ + 'SOQLs cannot be placed too close to any for loop', + 'Triggers must delegate to business logic to implement logic', + 'Apex classes should not exceed 1000 lines of code', + 'Apex class handling must not use the identified Apex/Logger framework', +]; + +export default function AIRuleFormModal(props: Readonly) { + const { isOpen, onClose, onSubmit } = props; + const [ruleName, setRuleName] = useState(''); + const [ruleKey, setRuleKey] = useState(''); + const [keyModifiedByUser, setKeyModifiedByUser] = useState(false); + const [ruleType, setRuleType] = useState('CODE_SMELL'); + const [severity, setSeverity] = useState('MAJOR'); + const [message, setMessage] = useState(''); + const [ruleDescription, setRuleDescription] = useState(''); + const [charCount, setCharCount] = useState(0); + + const handleSubmit = () => { + if (validateForm()) { + onSubmit({ + ruleName, + ruleKey, + ruleType, + severity, + message, + ruleDescription, + }); + } + }; + + const validateForm = (): boolean => { + return ( + ruleName.trim().length > 0 && + ruleKey.trim().length > 0 && + ruleType.length > 0 && + severity.length > 0 && + message.trim().length > 0 && + ruleDescription.trim().length >= MIN_CHAR_COUNT && + ruleDescription.trim().length <= MAX_CHAR_COUNT + ); + }; + + const typeOptions: LabelValueSelectOption[] = RULE_TYPES.map((type) => ({ + label: translate('issue.type', type), + value: type, + })); + + return ( + +
+ + AI Rule Generation +
+ Describe your coding standard in plain English. The AI will analyze your description + and automatically generate the rule syntax. +
+
+ + + ) => { + setRuleName(value); + if (!keyModifiedByUser) { + const generatedKey = latinize(value) + .replace(/[^A-Za-z0-9]/g, '_'); + setRuleKey(generatedKey); + } + }} + placeholder="e.g., Avoid Complex Methods" + size="full" + type="text" + value={ruleName} + /> + + + + + + +
+
+ + handleNameChange(e.target.value)} + autoFocus + /> + {submitted && !ruleName.trim() && ( +
+ + Rule name is required. +
+ )} +
+
+
+ + Rule Key* + + Auto-generated from name +
+ + {submitted && !ruleKey.trim() && ( +
+ + Rule key is required. +
+ )} +
+
+ + {/* Row 2: Type + Severity */} +
+
+
+ Rule Type +
+ value && setSeverity(value)} + data={SEVERITIES.map((sev) => ({ + label: sev.label, + value: sev.value, + prefix: , + }))} + value={severity} + valueIcon={} + /> +
+
+ + {/* Row 3: Message */} +
+
+ Message + Shown in violation reports +
+ setMessage(e.target.value)} + /> +
+ + {/* Row 4: Description */} +
+
+ + Rule Description* + + {charCount} characters +
+