]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-16141 Security hotspot status radio UI
authorGuillaume Peoc'h <guillaume.peoch@sonarsource.com>
Tue, 15 Mar 2022 11:05:08 +0000 (12:05 +0100)
committersonartech <sonartech@sonarsource.com>
Thu, 17 Mar 2022 20:03:09 +0000 (20:03 +0000)
server/sonar-web/src/main/js/app/styles/init/misc.css
server/sonar-web/src/main/js/apps/security-hotspots/components/HotspotViewer.css
server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusDescription.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/StatusSelectionRenderer.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/StatusDescription-test.tsx
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusDescription-test.tsx.snap
server/sonar-web/src/main/js/apps/security-hotspots/components/status/__tests__/__snapshots__/StatusSelectionRenderer-test.tsx.snap
server/sonar-web/src/main/js/components/controls/Radio.tsx

index ecb1d640698bd4695f84e2a1d1f31c71b97ae7d8..b5269470f8ad00063d52bba60aa0ce807fb5bd24 100644 (file)
@@ -489,6 +489,11 @@ th.huge-spacer-right {
   align-items: baseline;
 }
 
+.display-inline-flex-start {
+  display: inline-flex !important;
+  align-items: flex-start;
+}
+
 .display-inline-flex-center {
   display: inline-flex !important;
   align-items: center;
index 30cf6cd2522181335b88ac9d860b0f31d66e9a92..08bc04911653bfbf13e1355aac73b542d552c596 100644 (file)
@@ -33,3 +33,7 @@
 .hotspot-content .markdown {
   line-height: 1.8;
 }
+
+.status-radio i {
+  margin-top: 5px;
+}
index 63eb4abc3b94af04ae49e10cca54262a8903b82a..2f6ccbc222b7f08153326a6fc463c50f041afb5b 100644 (file)
@@ -18,6 +18,7 @@
  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
  */
 import styled from '@emotion/styled';
+import classNames from 'classnames';
 import * as React from 'react';
 import { translate } from '../../../../helpers/l10n';
 import { HotspotStatusOption } from '../../../../types/security-hotspots';
@@ -25,16 +26,19 @@ import { HotspotStatusOption } from '../../../../types/security-hotspots';
 export interface StatusDescriptionProps {
   statusOption: HotspotStatusOption;
   showTitle?: boolean;
+  statusInBadge?: boolean;
 }
 
 export default function StatusDescription(props: StatusDescriptionProps) {
-  const { statusOption, showTitle } = props;
+  const { statusOption, showTitle, statusInBadge = true } = props;
 
   return (
     <Container>
       <h3>
         {showTitle && `${translate('status')}: `}
-        <div className="badge">{translate('hotspots.status_option', statusOption)}</div>
+        <div className={classNames({ badge: statusInBadge })}>
+          {translate('hotspots.status_option', statusOption)}
+        </div>
       </h3>
       <div className="little-spacer-top">
         {translate('hotspots.status_option', statusOption, 'description')}
index e9af5ed7f5ebc852aa592c29cb218560007f8797..4260f4cc978180fa5fbfde928acdb6ea6908853f 100644 (file)
@@ -45,10 +45,11 @@ export default function StatusSelectionRenderer(props: StatusSelectionRendererPr
     return (
       <Radio
         checked={selectedStatus === status}
-        className="big-spacer-bottom"
+        className="big-spacer-bottom status-radio"
+        alignLabel={true}
         onCheck={props.onStatusChange}
         value={status}>
-        <StatusDescription statusOption={status} />
+        <StatusDescription statusOption={status} statusInBadge={false} />
       </Radio>
     );
   };
index 025b58e844e0552b8cbd4c6eeaff28fc21c4e838..8fca0afc6c52a137bbce59a64bc73fe276f1513f 100644 (file)
@@ -25,6 +25,7 @@ import StatusDescription, { StatusDescriptionProps } from '../StatusDescription'
 it('should render correctly', () => {
   expect(shallowRender()).toMatchSnapshot();
   expect(shallowRender({ showTitle: true })).toMatchSnapshot('with title');
+  expect(shallowRender({ statusInBadge: false })).toMatchSnapshot('without status in badge');
 });
 
 function shallowRender(props?: Partial<StatusDescriptionProps>) {
index 6eb6b70e5fbee1ae8593de78efd093f950048bff..a2062714e3bc9b8996afac4ce0c0f5ee75e16206 100644 (file)
@@ -34,3 +34,20 @@ exports[`should render correctly: with title 1`] = `
   </div>
 </Styled(div)>
 `;
+
+exports[`should render correctly: without status in badge 1`] = `
+<Styled(div)>
+  <h3>
+    <div
+      className=""
+    >
+      hotspots.status_option.TO_REVIEW
+    </div>
+  </h3>
+  <div
+    className="little-spacer-top"
+  >
+    hotspots.status_option.TO_REVIEW.description
+  </div>
+</Styled(div)>
+`;
index 0f1f287ca7709014a85e0d304e8c0b7765a8addd..d0f786cb32b9c0e8b147bbf0c60f9d67987c4a93 100644 (file)
@@ -8,42 +8,50 @@ exports[`should render correctly 1`] = `
     className="big-padded"
   >
     <Radio
+      alignLabel={true}
       checked={true}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="TO_REVIEW"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="TO_REVIEW"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="ACKNOWLEDGED"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="ACKNOWLEDGED"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="FIXED"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="FIXED"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="SAFE"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="SAFE"
       />
     </Radio>
@@ -88,42 +96,50 @@ exports[`should render correctly: loading 1`] = `
     className="big-padded"
   >
     <Radio
+      alignLabel={true}
       checked={true}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="TO_REVIEW"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="TO_REVIEW"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="ACKNOWLEDGED"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="ACKNOWLEDGED"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="FIXED"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="FIXED"
       />
     </Radio>
     <Radio
+      alignLabel={true}
       checked={false}
-      className="big-spacer-bottom"
+      className="big-spacer-bottom status-radio"
       onCheck={[MockFunction]}
       value="SAFE"
     >
       <StatusDescription
+        statusInBadge={false}
         statusOption="SAFE"
       />
     </Radio>
index 1af39aca0d25975c353bb3e9565dd495810328af..08891b07b671cc3816b7552e70bff5fa17e5c2fc 100644 (file)
@@ -24,6 +24,7 @@ import './Radio.css';
 interface Props {
   checked: boolean;
   className?: string;
+  alignLabel?: boolean;
   disabled?: boolean;
   onCheck: (value: string) => void;
   value: string;
@@ -39,12 +40,17 @@ export default class Radio extends React.PureComponent<Props> {
   };
 
   render() {
-    const { className, checked, children, disabled } = this.props;
+    const { className, checked, children, disabled, alignLabel = false } = this.props;
 
     return (
       <a
         aria-checked={checked}
-        className={classNames('display-inline-flex-center link-radio', className, { disabled })}
+        className={classNames(
+          alignLabel ? 'display-inline-flex-start' : 'display-inline-flex-center',
+          'link-radio',
+          className,
+          { disabled }
+        )}
         href="#"
         onClick={this.handleClick}
         role="radio">