From c13c409e59105e0187da35c14e7ba1d2e76a39a7 Mon Sep 17 00:00:00 2001 From: Kevin Silva Date: Mon, 18 Sep 2023 11:41:23 +0200 Subject: [PATCH] SONAR-20337 Validation fixes for QG --- .../src/components/avatar/GenericAvatar.tsx | 7 +- .../js/apps/quality-gates/components/App.tsx | 75 ++++++++++--------- .../components/CaycConditionsListItem.tsx | 5 +- .../ConditionReviewAndUpdateModal.tsx | 6 +- .../components/ConditionValueDescription.tsx | 2 +- .../quality-gates/components/Conditions.tsx | 7 +- .../components/CreateQualityGateForm.tsx | 1 + .../apps/quality-gates/components/Details.tsx | 3 +- .../components/DetailsContent.tsx | 2 +- .../js/apps/quality-gates/components/List.tsx | 4 +- .../quality-gates/components/Projects.tsx | 6 +- ...QualityGatePermissionsAddModalRenderer.tsx | 10 ++- .../QualityGatePermissionsRenderer.tsx | 7 +- .../controls/SelectListListContainer.tsx | 3 +- 14 files changed, 80 insertions(+), 58 deletions(-) diff --git a/server/sonar-web/design-system/src/components/avatar/GenericAvatar.tsx b/server/sonar-web/design-system/src/components/avatar/GenericAvatar.tsx index 38f4fbef6d9..2590ccbefdb 100644 --- a/server/sonar-web/design-system/src/components/avatar/GenericAvatar.tsx +++ b/server/sonar-web/design-system/src/components/avatar/GenericAvatar.tsx @@ -32,7 +32,12 @@ export interface GenericAvatarProps { size?: Size; } -export function GenericAvatar({ className, Icon, name, size = 'sm' }: GenericAvatarProps) { +export function GenericAvatar({ + className, + Icon, + name, + size = 'sm', +}: Readonly) { const theme = useTheme(); const text = name.length > 0 ? name[0].toUpperCase() : ''; diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx index d2781723d6a..4eaeb02b60f 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/App.tsx @@ -23,6 +23,8 @@ import { LAYOUT_FOOTER_HEIGHT, LAYOUT_GLOBAL_NAV_HEIGHT, LargeCenteredLayout, + PageContentFontWrapper, + Spinner, themeBorder, themeColor, } from 'design-system'; @@ -32,7 +34,6 @@ import { NavigateFunction, useNavigate, useParams } from 'react-router-dom'; import { fetchQualityGates } from '../../../api/quality-gates'; import Suggestions from '../../../components/embed-docs-modal/Suggestions'; import '../../../components/search-navigator.css'; -import Spinner from '../../../components/ui/Spinner'; import { translate, translateWithParameters } from '../../../helpers/l10n'; import { addSideBarClass, @@ -126,46 +127,48 @@ class App extends React.PureComponent { return ( - -
- - - - - - - - - - {name !== undefined && ( + + +
+ + -
+ + + + - )} -
+ + {name !== undefined && ( + +
+ + )} +
+
); } diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/CaycConditionsListItem.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/CaycConditionsListItem.tsx index 5dc0018f5f2..f3584343672 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/CaycConditionsListItem.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/CaycConditionsListItem.tsx @@ -23,7 +23,10 @@ import { CheckIcon, LightLabel } from 'design-system'; import * as React from 'react'; import { translate } from '../../../helpers/l10n'; -export default function CaycConditionsListItem({ index, last }: { index: number; last: boolean }) { +export default function CaycConditionsListItem({ + index, + last, +}: Readonly<{ index: number; last: boolean }>) { return (
  • diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionReviewAndUpdateModal.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionReviewAndUpdateModal.tsx index c65492aa462..1f9694811da 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionReviewAndUpdateModal.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionReviewAndUpdateModal.tsx @@ -42,7 +42,7 @@ interface Props { qualityGate: QualityGate; } -export default function CaycReviewUpdateConditionsModal(props: Props) { +export default function CaycReviewUpdateConditionsModal(props: Readonly) { const { conditions, qualityGate, @@ -56,12 +56,12 @@ export default function CaycReviewUpdateConditionsModal(props: Props) { const { weakConditions, missingConditions } = getWeakMissingAndNonCaycConditions(conditions); const sortedWeakConditions = sortBy( weakConditions, - (condition) => metrics[condition.metric] && metrics[condition.metric].name, + (condition) => metrics[condition.metric]?.name, ); const sortedMissingConditions = sortBy( missingConditions, - (condition) => metrics[condition.metric] && metrics[condition.metric].name, + (condition) => metrics[condition.metric]?.name, ); const getDocUrl = useDocUrl(); diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionValueDescription.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionValueDescription.tsx index 190f3bd8857..d3eb135958e 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionValueDescription.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/ConditionValueDescription.tsx @@ -51,7 +51,7 @@ function ConditionValueDescription({ appState: { settings }, metric, isToBeModified = false, -}: Props) { +}: Readonly) { if (condition.metric === MetricKey.new_maintainability_rating) { const maintainabilityGrid = getMaintainabilityGrid( settings[GlobalSettingKeys.RatingGrid] ?? '', diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx index 544c817564e..83d9dedee91 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Conditions.tsx @@ -87,6 +87,7 @@ export function Conditions({ const [editing, setEditing] = React.useState( qualityGate.caycStatus === CaycStatus.NonCompliant, ); + const { name } = qualityGate; const canEdit = Boolean(qualityGate.actions?.manageConditions); const { conditions = [] } = qualityGate; const existingConditions = conditions.filter((condition) => metrics[condition.metric]); @@ -111,9 +112,11 @@ export function Conditions({ const getDocUrl = useDocUrl(); + // set edit only when the name is change + // i.e when user changes the quality gate React.useEffect(() => { setEditing(qualityGate.caycStatus === CaycStatus.NonCompliant); - }, [qualityGate]); + }, [name]); // eslint-disable-line react-hooks/exhaustive-deps const renderConditionModal = React.useCallback( ({ onClose }: ModalProps) => { @@ -322,7 +325,7 @@ export function Conditions({ )} {qualityGate.caycStatus !== CaycStatus.NonCompliant && !editing && canEdit && ( -
    +
    { requiredAriaLabel={translate('field_required')} > -
    +
    {translate('quality_gates.projects')} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx index 92da185ae61..6c16f667f85 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/List.tsx @@ -73,7 +73,9 @@ export default function List({ qualityGates, currentQualityGate }: Props) { {(qualityGate.isDefault || qualityGate.isBuiltIn) && (
    - {qualityGate.isDefault && {translate('default')}} + {qualityGate.isDefault && ( + {translate('default')} + )} {qualityGate.isBuiltIn && }
    )} diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx index 7782337632b..0a7aef68925 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/Projects.tsx @@ -17,6 +17,8 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + +import { Note } from 'design-system'; import { find, without } from 'lodash'; import * as React from 'react'; import { @@ -131,14 +133,14 @@ export default class Projects extends React.PureComponent { renderElement = (key: string): React.ReactNode => { const project = find(this.state.projects, { key }); return ( -
    +
    {project === undefined ? ( key ) : ( <> {project.name}
    - {project.key} + {project.key} )}
    diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx index 9dcfd8eb17a..42c02834648 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsAddModalRenderer.tsx @@ -23,6 +23,7 @@ import { GenericAvatar, LabelValueSelectOption, Modal, + Note, SearchSelectDropdown, UserGroupIcon, } from 'design-system'; @@ -49,7 +50,7 @@ const FORM_ID = 'quality-gate-permissions-add-modal'; const USER_SELECT_INPUT_ID = 'quality-gate-permissions-add-modal-select-input'; export default function QualityGatePermissionsAddModalRenderer( - props: QualityGatePermissionsAddModalRendererProps, + props: Readonly, ) { const { selection, submitting } = props; @@ -68,6 +69,7 @@ export default function QualityGatePermissionsAddModalRenderer( htmlFor={USER_SELECT_INPUT_ID} > ) { if (!option) { return null; } @@ -118,7 +120,7 @@ function OptionRenderer({ /> {option.name} - {option.login} + {option.login} ) : ( diff --git a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx index 5434dd3736c..877bfa4aadc 100644 --- a/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx +++ b/server/sonar-web/src/main/js/apps/quality-gates/components/QualityGatePermissionsRenderer.tsx @@ -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 classNames from 'classnames'; import { ButtonSecondary, DangerButtonPrimary, @@ -60,8 +61,8 @@ export default function QualityGatePermissionsRenderer(props: QualityGatePermiss {translate('quality_gates.permissions')} -

    {translate('quality_gates.permissions.help')}

    -
    +

    {translate('quality_gates.permissions.help')}

    +
    0 })}> {users.map((user) => ( @@ -78,7 +79,7 @@ export default function QualityGatePermissionsRenderer(props: QualityGatePermiss - + {translate('quality_gates.permissions.grant')} diff --git a/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx b/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx index 033a6aeed1c..f68b0e6e623 100644 --- a/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx +++ b/server/sonar-web/src/main/js/components/controls/SelectListListContainer.tsx @@ -19,7 +19,6 @@ */ import styled from '@emotion/styled'; import { Checkbox, ListItem, UnorderedList, themeBorder } from 'design-system'; -import { uniqueId } from 'lodash'; import * as React from 'react'; import { translate } from '../../helpers/l10n'; import { SelectListFilter } from './SelectList'; @@ -111,7 +110,7 @@ export default class SelectListListContainer extends React.PureComponent