From 98df714a69543ea61f8c80b61c94ffb164b46ca9 Mon Sep 17 00:00:00 2001 From: Revanshu Paliwal Date: Wed, 14 Jun 2023 15:20:12 +0200 Subject: [PATCH] SONAR-19581 Styling fixes for issue list and details page --- .../src/components/DiscreetSelect.tsx | 3 +- .../src/components/InputSelect.tsx | 5 +- .../code-line/LineIssuesIndicatorIcon.tsx | 3 +- .../src/components/icons/IssueTypeIcon.tsx | 3 +- .../design-system/src/types/index.ts | 1 + .../design-system/src/types/issues.ts | 21 +++++ .../components/ComponentBreadcrumbs.tsx | 8 +- .../js/apps/issues/components/IssueHeader.tsx | 1 - .../main/js/components/icons/StatusIcon.tsx | 86 +++++-------------- .../src/main/js/components/issue/Issue.css | 4 - .../issue/components/IssueActionsBar.tsx | 20 ++++- .../issue/components/IssueCommentAction.tsx | 6 +- .../issue/components/IssueSeverity.tsx | 17 ++-- .../issue/components/IssueTransition.tsx | 47 +++++----- .../components/issue/components/IssueType.tsx | 9 +- .../components/issue/components/IssueView.tsx | 17 ++-- 16 files changed, 130 insertions(+), 121 deletions(-) create mode 100644 server/sonar-web/design-system/src/types/issues.ts diff --git a/server/sonar-web/design-system/src/components/DiscreetSelect.tsx b/server/sonar-web/design-system/src/components/DiscreetSelect.tsx index b78deb33a91..085caf1b12b 100644 --- a/server/sonar-web/design-system/src/components/DiscreetSelect.tsx +++ b/server/sonar-web/design-system/src/components/DiscreetSelect.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 styled from '@emotion/styled'; import tw from 'twin.macro'; import { themeBorder, themeColor, themeContrast } from '../helpers/theme'; @@ -25,7 +26,7 @@ import { InputSelect, LabelValueSelectOption } from './InputSelect'; interface Props { className?: string; - components?: any; + components?: Parameters[0]['components']; customValue?: JSX.Element; isDisabled?: boolean; menuIsOpen?: boolean; diff --git a/server/sonar-web/design-system/src/components/InputSelect.tsx b/server/sonar-web/design-system/src/components/InputSelect.tsx index 906203174dd..f000f732136 100644 --- a/server/sonar-web/design-system/src/components/InputSelect.tsx +++ b/server/sonar-web/design-system/src/components/InputSelect.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 { useTheme as themeInfo } from '@emotion/react'; import classNames from 'classnames'; import { omit } from 'lodash'; @@ -120,11 +121,11 @@ export function InputSelect< classNames={{ container: () => 'sw-relative sw-inline-block sw-align-middle', placeholder: () => 'sw-truncate sw-leading-4', - menu: () => 'sw-z-dropdown-menu', + menu: () => 'sw-z-dropdown-menu sw-ml-1/2 sw-mt-2', menuList: () => 'sw-overflow-y-auto sw-py-2 sw-max-h-[12.25rem]', control: ({ isDisabled }) => classNames( - 'sw-absolut sw-box-border sw-rounded-2 sw-overflow-hidden', + 'sw-box-border sw-rounded-2 sw-overflow-hidden', isDisabled && 'sw-pointer-events-none sw-cursor-not-allowed' ), option: ({ isDisabled }) => diff --git a/server/sonar-web/design-system/src/components/code-line/LineIssuesIndicatorIcon.tsx b/server/sonar-web/design-system/src/components/code-line/LineIssuesIndicatorIcon.tsx index a5522960a15..792722caa5f 100644 --- a/server/sonar-web/design-system/src/components/code-line/LineIssuesIndicatorIcon.tsx +++ b/server/sonar-web/design-system/src/components/code-line/LineIssuesIndicatorIcon.tsx @@ -20,10 +20,9 @@ import styled from '@emotion/styled'; import { memo } from 'react'; import tw from 'twin.macro'; +import { IssueType } from '../../types'; import { IssueTypeIcon } from '../icons/IssueTypeIcon'; -export type IssueType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT'; - interface Props { issuesCount: number; mostImportantIssueType: IssueType; diff --git a/server/sonar-web/design-system/src/components/icons/IssueTypeIcon.tsx b/server/sonar-web/design-system/src/components/icons/IssueTypeIcon.tsx index 134788f9618..94047ec41c7 100644 --- a/server/sonar-web/design-system/src/components/icons/IssueTypeIcon.tsx +++ b/server/sonar-web/design-system/src/components/icons/IssueTypeIcon.tsx @@ -17,17 +17,18 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { useTheme } from '@emotion/react'; import styled from '@emotion/styled'; import tw from 'twin.macro'; import { themeColor, themeContrast } from '../../helpers/theme'; +import { IssueType } from '../../types'; import { BugIcon } from './BugIcon'; import { CodeSmellIcon } from './CodeSmellIcon'; import { IconProps } from './Icon'; import { SecurityFindingIcon } from './SecurityFindingIcon'; import { VulnerabilityIcon } from './VulnerabilityIcon'; -export type IssueType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT'; export interface Props extends IconProps { // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents type: string | IssueType; diff --git a/server/sonar-web/design-system/src/types/index.ts b/server/sonar-web/design-system/src/types/index.ts index 60861305544..7a5670450c2 100644 --- a/server/sonar-web/design-system/src/types/index.ts +++ b/server/sonar-web/design-system/src/types/index.ts @@ -19,5 +19,6 @@ */ export * from './charts'; +export * from './issues'; export * from './measures'; export * from './theme'; diff --git a/server/sonar-web/design-system/src/types/issues.ts b/server/sonar-web/design-system/src/types/issues.ts new file mode 100644 index 00000000000..8f2c801254a --- /dev/null +++ b/server/sonar-web/design-system/src/types/issues.ts @@ -0,0 +1,21 @@ +/* + * SonarQube + * Copyright (C) 2009-2023 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. + */ + +export type IssueType = 'BUG' | 'VULNERABILITY' | 'CODE_SMELL' | 'SECURITY_HOTSPOT'; diff --git a/server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx b/server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx index c6beaa5f4d1..777284552d0 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/ComponentBreadcrumbs.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 styled from '@emotion/styled'; import { Badge, themeBorder, themeColor, themeContrast } from 'design-system'; import * as React from 'react'; @@ -63,6 +64,7 @@ export default function ComponentBreadcrumbs({ {displayProject && ( {limitComponentName(issue.projectName)} + {displayBranchInformation && ( <> {' - '} @@ -76,18 +78,20 @@ export default function ComponentBreadcrumbs({ )} )} + )} - {collapsePath(componentName || '')} + {collapsePath(componentName ?? '')} ); } const DivStyled = styled.div` - color: ${themeContrast('subnavigation')}; background-color: ${themeColor('subnavigation')}; + color: ${themeContrast('breadcrumb')}; + &:not(:last-child) { border-bottom: ${themeBorder('default')}; } diff --git a/server/sonar-web/src/main/js/apps/issues/components/IssueHeader.tsx b/server/sonar-web/src/main/js/apps/issues/components/IssueHeader.tsx index 4715c45f807..5f2e86919c0 100644 --- a/server/sonar-web/src/main/js/apps/issues/components/IssueHeader.tsx +++ b/server/sonar-web/src/main/js/apps/issues/components/IssueHeader.tsx @@ -168,7 +168,6 @@ export default class IssueHeader extends React.PureComponent { /> React.ReactElement> = { - open: OpenStatusIcon, - confirmed: ConfirmedStatusIcon, - reopened: ReopenedStatusIcon, - resolved: ResolvedStatusIcon, - closed: ClosedStatusIcon, - to_review: OpenStatusIcon, - in_review: ConfirmedStatusIcon, - reviewed: ResolvedStatusIcon, + closed: StatusResolvedIcon, + confirm: StatusConfirmedIcon, + confirmed: StatusConfirmedIcon, + falsepositive: StatusResolvedIcon, + in_review: StatusConfirmedIcon, + open: StatusOpenIcon, + reopened: StatusReopenedIcon, + resolve: StatusResolvedIcon, + resolved: StatusResolvedIcon, + reviewed: StatusResolvedIcon, + to_review: StatusOpenIcon, + wontfix: StatusResolvedIcon, }; export default function StatusIcon({ status, ...iconProps }: Props) { const DesiredStatusIcon = statusIcons[status.toLowerCase()]; - return DesiredStatusIcon ? : null; -} - -function OpenStatusIcon(iconProps: IconProps) { - return ( - - - - ); -} - -function ConfirmedStatusIcon(iconProps: IconProps) { - return ( - - - - ); -} - -function ReopenedStatusIcon(iconProps: IconProps) { - return ( - - - - ); -} -function ResolvedStatusIcon(iconProps: IconProps) { - return ( - - - - ); -} - -function ClosedStatusIcon(iconProps: IconProps) { - return ( - - - - ); + return DesiredStatusIcon ? : null; } diff --git a/server/sonar-web/src/main/js/components/issue/Issue.css b/server/sonar-web/src/main/js/components/issue/Issue.css index 5be5920c71f..4a0abde9f66 100644 --- a/server/sonar-web/src/main/js/components/issue/Issue.css +++ b/server/sonar-web/src/main/js/components/issue/Issue.css @@ -93,10 +93,6 @@ margin-left: var(--gridSize); } -.issue-header-actions .issue-meta + .issue-meta { - margin-left: calc(var(--gridSize) * 2); -} - .issue-meta-label { display: inline-block; vertical-align: top; diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx index 76fa0f85231..e0008c255b5 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/IssueActionsBar.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 styled from '@emotion/styled'; import classNames from 'classnames'; import { Badge, CommentIcon, SeparatorCircleIcon, themeColor } from 'design-system'; @@ -71,6 +72,7 @@ export default function IssueActionsBar(props: Props) { showCommentsInPopup, showLine, } = props; + const [commentState, setCommentState] = React.useState({ commentAutoTriggered: false, commentPlaceholder: '', @@ -86,19 +88,22 @@ export default function IssueActionsBar(props: Props) { const newIssue = { ...issue, [property]: value }; updateIssue(onChange, apiCall({ issue: issue.key, [property]: value }), issue, newIssue); } + togglePopup(popup, false); }; - const toggleComment = (open: boolean | undefined, placeholder = '', autoTriggered = false) => { + const toggleComment = (open: boolean, placeholder = '', autoTriggered = false) => { setCommentState({ commentPlaceholder: placeholder, commentAutoTriggered: autoTriggered, }); + togglePopup('comment', open); }; const handleTransition = (issue: Issue) => { onChange(issue); + if ( issue.resolution === IssueResolution.FalsePositive || (issue.resolution === IssueResolution.WontFix && issue.type !== IssueTypeEnum.SecurityHotspot) @@ -108,15 +113,18 @@ export default function IssueActionsBar(props: Props) { }; const { externalRulesRepoNames } = React.useContext(WorkspaceContext); + const ruleEngine = (issue.externalRuleEngine && externalRulesRepoNames[issue.externalRuleEngine]) || issue.externalRuleEngine; + const canAssign = issue.actions.includes(IssueActions.Assign); const canComment = issue.actions.includes(IssueActions.Comment); const canSetSeverity = issue.actions.includes(IssueActions.SetSeverity); const canSetType = issue.actions.includes(IssueActions.SetType); const hasTransitions = issue.transitions.length > 0; const hasComments = !!issue.comments?.length; + const issueMetaListItemClassNames = classNames( className, 'sw-body-sm sw-overflow-hidden sw-whitespace-nowrap sw-max-w-abs-150' @@ -130,6 +138,7 @@ export default function IssueActionsBar(props: Props) {
  • +
  • +
  • +
  • + {(canComment || showCommentsInPopup) && ( {issue.comments?.length} + )} + {showLine && isDefined(issue.textRange) && ( <> @@ -221,17 +235,21 @@ export default function IssueActionsBar(props: Props) { {translateWithParameters('issue.ncloc_x.short', issue.textRange.endLine)} + )} + {issue.effort && ( <> {translateWithParameters('issue.x_effort', issue.effort)} + )} + diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.tsx index 17ccba55a76..54fc8d609f7 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/IssueCommentAction.tsx @@ -32,7 +32,7 @@ interface Props { currentPopup?: boolean; issueKey: string; onChange: (issue: Issue) => void; - toggleComment: (open?: boolean, placeholder?: string, autoTriggered?: boolean) => void; + toggleComment: (open: boolean, placeholder?: string, autoTriggered?: boolean) => void; comments?: IssueComment[]; showCommentsInPopup?: boolean; } @@ -54,10 +54,6 @@ export default class IssueCommentAction extends React.PureComponent { updateIssue(this.props.onChange, deleteIssueComment({ comment })); }; - handleCommentClick = () => { - this.props.toggleComment(); - }; - handleClose = () => { this.props.toggleComment(false); }; diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx index 7d3b33a8230..1c80407309b 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/IssueSeverity.tsx @@ -17,13 +17,15 @@ * along with this program; if not, write to the Free Software Foundation, * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + import { DiscreetSelect } from 'design-system'; import * as React from 'react'; import { setIssueSeverity } from '../../../api/issues'; +import { SEVERITIES } from '../../../helpers/constants'; import { translate, translateWithParameters } from '../../../helpers/l10n'; -import { IssueResponse } from '../../../types/issues'; +import { IssueResponse, IssueSeverity as IssueSeverityType } from '../../../types/issues'; import { Issue, RawQuery } from '../../../types/types'; -import SeverityIcon from '../../icons/SeverityIcon'; +import IssueSeverityIcon from '../../icon-mappers/IssueSeverityIcon'; interface Props { canSetSeverity: boolean; @@ -44,7 +46,7 @@ export default class IssueSeverity extends React.PureComponent { this.toggleSetSeverity(false); }; - toggleSetSeverity = (open?: boolean) => { + toggleSetSeverity = (open: boolean) => { this.props.togglePopup('set-severity', open); }; @@ -54,11 +56,11 @@ export default class IssueSeverity extends React.PureComponent { render() { const { issue } = this.props; - const SEVERITY = ['BLOCKER', 'CRITICAL', 'MAJOR', 'MINOR', 'INFO']; - const typesOptions = SEVERITY.map((severity) => ({ + + const typesOptions = SEVERITIES.map((severity) => ({ label: translate('severity', severity), value: severity, - Icon: , + Icon: , })); if (this.props.canSetSeverity) { @@ -81,7 +83,8 @@ export default class IssueSeverity extends React.PureComponent { return ( - + + {translate('severity', issue.severity)} ); diff --git a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx b/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx index a6b505c716d..338b5a6c344 100644 --- a/server/sonar-web/src/main/js/components/issue/components/IssueTransition.tsx +++ b/server/sonar-web/src/main/js/components/issue/components/IssueTransition.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 { DiscreetSelect } from 'design-system'; import * as React from 'react'; import { GroupBase, OptionProps, components } from 'react-select'; @@ -36,16 +37,36 @@ interface Props { togglePopup: (popup: string, show?: boolean) => void; } +function SingleValueFactory(issue: Props['issue']) { + return function SingleValue< + V, + Option extends LabelValueSelectOption, + IsMulti extends boolean = false, + Group extends GroupBase