]> source.dussan.org Git - sonarqube.git/commitdiff
SONAR-12797 Handle branch parameter
authorJeremy <jeremy.davis@sonarsource.com>
Mon, 6 Jan 2020 15:58:38 +0000 (16:58 +0100)
committerSonarTech <sonartech@sonarsource.com>
Mon, 13 Jan 2020 19:46:35 +0000 (20:46 +0100)
SONAR-12719:
* Prevent action button text from wrapping
* Conditional submit button label

13 files changed:
server/sonar-web/src/main/js/api/security-hotspots.ts
server/sonar-web/src/main/js/apps/securityHotspots/SecurityHotspotsApp.tsx
server/sonar-web/src/main/js/apps/securityHotspots/__tests__/SecurityHotspotsApp-test.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/HotspotActions.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/HotspotActionsForm.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/HotspotActionsFormRenderer.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/HotspotActionsForm-test.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/HotspotActionsFormRenderer-test.tsx
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/__snapshots__/HotspotActions-test.tsx.snap
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/__snapshots__/HotspotActionsForm-test.tsx.snap
server/sonar-web/src/main/js/apps/securityHotspots/components/__tests__/__snapshots__/HotspotActionsFormRenderer-test.tsx.snap
server/sonar-web/src/main/js/types/security-hotspots.ts
sonar-core/src/main/resources/org/sonar/l10n/core.properties

index 6f266bb780182139066fc1b51920f3f6852c990c..c4518a65d619badb43a464796cd91c5f7c14336c 100644 (file)
@@ -59,8 +59,15 @@ export function getSecurityHotspots(
   return getJSON('/api/hotspots/search', data).catch(throwGlobalError);
 }
 
-export function getSecurityHotspotList(hotspotKeys: string[]): Promise<HotspotSearchResponse> {
-  return getJSON('/api/hotspots/search', { hotspots: hotspotKeys.join() }).catch(throwGlobalError);
+export function getSecurityHotspotList(
+  hotspotKeys: string[],
+  data: {
+    projectKey: string;
+  } & BranchParameters
+): Promise<HotspotSearchResponse> {
+  return getJSON('/api/hotspots/search', { ...data, hotspots: hotspotKeys.join() }).catch(
+    throwGlobalError
+  );
 }
 
 export function getSecurityHotspotDetails(securityHotspotKey: string): Promise<Hotspot> {
index 0060c223e4a2e7cdb9fb747869208ff06a63d760..1e8f7221f4ad530faab23fcf8b1e9328217a0db6 100644 (file)
@@ -157,7 +157,10 @@ export class SecurityHotspotsApp extends React.PureComponent<Props, State> {
     this.setState({ hotspotKeys });
 
     if (hotspotKeys && hotspotKeys.length > 0) {
-      return getSecurityHotspotList(hotspotKeys);
+      return getSecurityHotspotList(hotspotKeys, {
+        projectKey: component.key,
+        ...getBranchLikeQuery(branchLike)
+      });
     }
 
     const status =
index eed79943cbb1046a083390343e44bc33f8151c38..15315cd7c8fa18dbcd2d12baf5d9769d112803b3 100644 (file)
@@ -113,7 +113,10 @@ it('should load data correctly when hotspot key list is forced', async () => {
   });
 
   await waitAndUpdate(wrapper);
-  expect(getSecurityHotspotList).toBeCalledWith(hotspotKeys);
+  expect(getSecurityHotspotList).toBeCalledWith(hotspotKeys, {
+    projectKey: 'my-project',
+    branch: 'branch-6.7'
+  });
   expect(wrapper.state().hotspotKeys).toEqual(hotspotKeys);
   expect(wrapper.find(SecurityHotspotsAppRenderer).props().isStaticListOfHotspots).toBeTruthy();
 
index bca775c9ad78b0c8ecd144800249446190f5b853..87cff37e935a726f460dff142d580dbb10c4e2bc 100644 (file)
@@ -53,7 +53,7 @@ export default function HotspotActions(props: HotspotActionsProps) {
   });
 
   return (
-    <div className="dropdown">
+    <div className="dropdown big-spacer-left flex-0">
       <Button onClick={() => setOpen(!open)}>
         {translate('hotspot.change_status', hotspot.status)}
         <DropdownIcon className="little-spacer-left" />
@@ -63,7 +63,7 @@ export default function HotspotActions(props: HotspotActionsProps) {
         <OutsideClickHandler onClickOutside={() => setOpen(false)}>
           <DropdownOverlay placement={PopupPlacement.BottomRight}>
             <HotspotActionsForm
-              hotspotKey={hotspot.key}
+              hotspot={hotspot}
               onSubmit={data => {
                 setOpen(false);
                 props.onSubmit(data);
index 82c36be3dc9912a50bb58efa7f61d6cd6a500e15..1787fa9e1a23e0780c2a2a82164119965faabc88 100644 (file)
@@ -20,6 +20,7 @@
 import * as React from 'react';
 import { assignSecurityHotspot, setSecurityHotspotStatus } from '../../../api/security-hotspots';
 import {
+  Hotspot,
   HotspotResolution,
   HotspotSetStatusRequest,
   HotspotStatus,
@@ -29,7 +30,7 @@ import {
 import HotspotActionsFormRenderer from './HotspotActionsFormRenderer';
 
 interface Props {
-  hotspotKey: string;
+  hotspot: Hotspot;
   onSubmit: (data: HotspotUpdateFields) => void;
 }
 
@@ -62,7 +63,7 @@ export default class HotspotActionsForm extends React.Component<Props, State> {
   handleSubmit = (event: React.SyntheticEvent<HTMLFormElement>) => {
     event.preventDefault();
 
-    const { hotspotKey } = this.props;
+    const { hotspot } = this.props;
     const { comment, selectedOption, selectedUser } = this.state;
 
     const status =
@@ -82,7 +83,7 @@ export default class HotspotActionsForm extends React.Component<Props, State> {
     }
 
     this.setState({ submitting: true });
-    return setSecurityHotspotStatus(hotspotKey, data)
+    return setSecurityHotspotStatus(hotspot.key, data)
       .then(() => {
         if (selectedOption === HotspotStatusOption.ADDITIONAL_REVIEW && selectedUser) {
           return this.assignHotspot(selectedUser, comment);
@@ -98,22 +99,22 @@ export default class HotspotActionsForm extends React.Component<Props, State> {
   };
 
   assignHotspot = (assignee: T.UserActive, comment: string) => {
-    const { hotspotKey } = this.props;
+    const { hotspot } = this.props;
 
-    return assignSecurityHotspot(hotspotKey, {
+    return assignSecurityHotspot(hotspot.key, {
       assignee: assignee.login,
       comment
     });
   };
 
   render() {
-    const { hotspotKey } = this.props;
+    const { hotspot } = this.props;
     const { comment, selectedOption, selectedUser, submitting } = this.state;
 
     return (
       <HotspotActionsFormRenderer
         comment={comment}
-        hotspotKey={hotspotKey}
+        hotspotStatus={hotspot.status}
         onAssign={this.handleAssign}
         onChangeComment={this.handleCommentChange}
         onSelectOption={this.handleSelectOption}
index d3f39cb72642ff6e27a898e8a3ddac9c8cc040e6..b231c6b829daa7c3e78e286ad0812cac657d036e 100644 (file)
@@ -22,12 +22,12 @@ import { SubmitButton } from 'sonar-ui-common/components/controls/buttons';
 import Radio from 'sonar-ui-common/components/controls/Radio';
 import { translate } from 'sonar-ui-common/helpers/l10n';
 import MarkdownTips from '../../../components/common/MarkdownTips';
-import { HotspotStatusOption } from '../../../types/security-hotspots';
+import { HotspotStatus, HotspotStatusOption } from '../../../types/security-hotspots';
 import HotspotAssigneeSelect from './HotspotAssigneeSelect';
 
 export interface HotspotActionsFormRendererProps {
   comment: string;
-  hotspotKey: string;
+  hotspotStatus: HotspotStatus;
   onAssign: (user: T.UserActive) => void;
   onChangeComment: (comment: string) => void;
   onSelectOption: (option: HotspotStatusOption) => void;
@@ -38,7 +38,7 @@ export interface HotspotActionsFormRendererProps {
 }
 
 export default function HotspotActionsFormRenderer(props: HotspotActionsFormRendererProps) {
-  const { comment, selectedOption, submitting } = props;
+  const { comment, hotspotStatus, selectedOption, submitting } = props;
 
   return (
     <form className="abs-width-400 padded" onSubmit={props.onSubmit}>
@@ -69,8 +69,8 @@ export default function HotspotActionsFormRenderer(props: HotspotActionsFormRend
       <div className="display-flex-column big-spacer-bottom">
         <label className="little-spacer-bottom">{translate('hotspots.form.comment')}</label>
         <textarea
-          className="form-field fixed-width spacer-bottom"
           autoFocus={true}
+          className="form-field fixed-width spacer-bottom"
           onChange={(event: React.ChangeEvent<HTMLTextAreaElement>) =>
             props.onChangeComment(event.currentTarget.value)
           }
@@ -86,7 +86,9 @@ export default function HotspotActionsFormRenderer(props: HotspotActionsFormRend
       </div>
       <div className="text-right">
         {submitting && <i className="spinner spacer-right" />}
-        <SubmitButton disabled={submitting}>{translate('hotspots.form.submit')}</SubmitButton>
+        <SubmitButton disabled={submitting}>
+          {translate('hotspots.form.submit', hotspotStatus)}
+        </SubmitButton>
       </div>
     </form>
   );
index 0672795ddd2a3542f4c2a86d9691e158fdc76b66..f5370b21e78c9d1bc3d81eadc64c9aec18b0d8ae 100644 (file)
@@ -21,6 +21,7 @@ import { shallow } from 'enzyme';
 import * as React from 'react';
 import { waitAndUpdate } from 'sonar-ui-common/helpers/testUtils';
 import { assignSecurityHotspot, setSecurityHotspotStatus } from '../../../../api/security-hotspots';
+import { mockHotspot } from '../../../../helpers/mocks/security-hotspots';
 import { mockLoggedInUser } from '../../../../helpers/testMocks';
 import {
   HotspotResolution,
@@ -128,6 +129,6 @@ it('should handle submit failure', async () => {
 
 function shallowRender(props: Partial<HotspotActionsForm['props']> = {}) {
   return shallow<HotspotActionsForm>(
-    <HotspotActionsForm hotspotKey="key" onSubmit={jest.fn()} {...props} />
+    <HotspotActionsForm hotspot={mockHotspot({ key: 'key' })} onSubmit={jest.fn()} {...props} />
   );
 }
index 3a6a907d5e7b0489614729ab5a5147217ee4b022..ea8d4cd4cb6f20d57537cd59b9b8f05259427c80 100644 (file)
@@ -20,7 +20,7 @@
 import { shallow } from 'enzyme';
 import * as React from 'react';
 import { mockLoggedInUser } from '../../../../helpers/testMocks';
-import { HotspotStatusOption } from '../../../../types/security-hotspots';
+import { HotspotStatus, HotspotStatusOption } from '../../../../types/security-hotspots';
 import HotspotActionsForm from '../HotspotActionsForm';
 import HotspotActionsFormRenderer, {
   HotspotActionsFormRendererProps
@@ -44,7 +44,7 @@ function shallowRender(props: Partial<HotspotActionsFormRendererProps> = {}) {
   return shallow<HotspotActionsForm>(
     <HotspotActionsFormRenderer
       comment="written comment"
-      hotspotKey="key"
+      hotspotStatus={HotspotStatus.TO_REVIEW}
       onAssign={jest.fn()}
       onChangeComment={jest.fn()}
       onSelectOption={jest.fn()}
index 4ba0565be9ad49616462dc265b22fd5e903f2541..657718ecd2c59dc92d38455e4c029b292fc20e60 100644 (file)
@@ -2,7 +2,7 @@
 
 exports[`should open when clicked 1`] = `
 <div
-  className="dropdown"
+  className="dropdown big-spacer-left flex-0"
 >
   <Button
     onClick={[Function]}
@@ -19,7 +19,104 @@ exports[`should open when clicked 1`] = `
       placement="bottom-right"
     >
       <HotspotActionsForm
-        hotspotKey="key"
+        hotspot={
+          Object {
+            "assignee": "assignee",
+            "assigneeUser": Object {
+              "active": true,
+              "local": true,
+              "login": "assignee",
+              "name": "John Doe",
+            },
+            "author": "author",
+            "authorUser": Object {
+              "active": true,
+              "local": true,
+              "login": "author",
+              "name": "John Doe",
+            },
+            "changelog": Array [],
+            "comment": Array [],
+            "component": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "FIL",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "creationDate": "2013-05-13T17:55:41+0200",
+            "key": "key",
+            "line": 142,
+            "message": "'3' is a magic number.",
+            "project": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "TRK",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "resolution": "FIXED",
+            "rule": Object {
+              "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+              "key": "squid:S2077",
+              "name": "That rule",
+              "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+              "securityCategory": "sql-injection",
+              "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+              "vulnerabilityProbability": "HIGH",
+            },
+            "status": "TO_REVIEW",
+            "textRange": Object {
+              "endLine": 142,
+              "endOffset": 83,
+              "startLine": 142,
+              "startOffset": 26,
+            },
+            "updateDate": "2013-05-13T17:55:42+0200",
+            "users": Array [
+              Object {
+                "active": true,
+                "local": true,
+                "login": "assignee",
+                "name": "John Doe",
+              },
+              Object {
+                "active": true,
+                "local": true,
+                "login": "author",
+                "name": "John Doe",
+              },
+            ],
+          }
+        }
         onSubmit={[Function]}
       />
     </DropdownOverlay>
@@ -29,7 +126,7 @@ exports[`should open when clicked 1`] = `
 
 exports[`should register an eventlistener: Dropdown closed 1`] = `
 <div
-  className="dropdown"
+  className="dropdown big-spacer-left flex-0"
 >
   <Button
     onClick={[Function]}
@@ -44,7 +141,7 @@ exports[`should register an eventlistener: Dropdown closed 1`] = `
 
 exports[`should register an eventlistener: Dropdown open 1`] = `
 <div
-  className="dropdown"
+  className="dropdown big-spacer-left flex-0"
 >
   <Button
     onClick={[Function]}
@@ -61,7 +158,104 @@ exports[`should register an eventlistener: Dropdown open 1`] = `
       placement="bottom-right"
     >
       <HotspotActionsForm
-        hotspotKey="key"
+        hotspot={
+          Object {
+            "assignee": "assignee",
+            "assigneeUser": Object {
+              "active": true,
+              "local": true,
+              "login": "assignee",
+              "name": "John Doe",
+            },
+            "author": "author",
+            "authorUser": Object {
+              "active": true,
+              "local": true,
+              "login": "author",
+              "name": "John Doe",
+            },
+            "changelog": Array [],
+            "comment": Array [],
+            "component": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "FIL",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "creationDate": "2013-05-13T17:55:41+0200",
+            "key": "key",
+            "line": 142,
+            "message": "'3' is a magic number.",
+            "project": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "TRK",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "resolution": "FIXED",
+            "rule": Object {
+              "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+              "key": "squid:S2077",
+              "name": "That rule",
+              "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+              "securityCategory": "sql-injection",
+              "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+              "vulnerabilityProbability": "HIGH",
+            },
+            "status": "TO_REVIEW",
+            "textRange": Object {
+              "endLine": 142,
+              "endOffset": 83,
+              "startLine": 142,
+              "startOffset": 26,
+            },
+            "updateDate": "2013-05-13T17:55:42+0200",
+            "users": Array [
+              Object {
+                "active": true,
+                "local": true,
+                "login": "assignee",
+                "name": "John Doe",
+              },
+              Object {
+                "active": true,
+                "local": true,
+                "login": "author",
+                "name": "John Doe",
+              },
+            ],
+          }
+        }
         onSubmit={[Function]}
       />
     </DropdownOverlay>
@@ -71,7 +265,7 @@ exports[`should register an eventlistener: Dropdown open 1`] = `
 
 exports[`should register an eventlistener: Dropdown still open 1`] = `
 <div
-  className="dropdown"
+  className="dropdown big-spacer-left flex-0"
 >
   <Button
     onClick={[Function]}
@@ -88,7 +282,104 @@ exports[`should register an eventlistener: Dropdown still open 1`] = `
       placement="bottom-right"
     >
       <HotspotActionsForm
-        hotspotKey="key"
+        hotspot={
+          Object {
+            "assignee": "assignee",
+            "assigneeUser": Object {
+              "active": true,
+              "local": true,
+              "login": "assignee",
+              "name": "John Doe",
+            },
+            "author": "author",
+            "authorUser": Object {
+              "active": true,
+              "local": true,
+              "login": "author",
+              "name": "John Doe",
+            },
+            "changelog": Array [],
+            "comment": Array [],
+            "component": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "FIL",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "creationDate": "2013-05-13T17:55:41+0200",
+            "key": "key",
+            "line": 142,
+            "message": "'3' is a magic number.",
+            "project": Object {
+              "breadcrumbs": Array [],
+              "key": "my-project",
+              "name": "MyProject",
+              "organization": "foo",
+              "qualifier": "TRK",
+              "qualityGate": Object {
+                "isDefault": true,
+                "key": "30",
+                "name": "Sonar way",
+              },
+              "qualityProfiles": Array [
+                Object {
+                  "deleted": false,
+                  "key": "my-qp",
+                  "language": "ts",
+                  "name": "Sonar way",
+                },
+              ],
+              "tags": Array [],
+            },
+            "resolution": "FIXED",
+            "rule": Object {
+              "fixRecommendations": "<p>This a <strong>strong</strong> message about fixing !</p>",
+              "key": "squid:S2077",
+              "name": "That rule",
+              "riskDescription": "<p>This a <strong>strong</strong> message about risk !</p>",
+              "securityCategory": "sql-injection",
+              "vulnerabilityDescription": "<p>This a <strong>strong</strong> message about vulnerability !</p>",
+              "vulnerabilityProbability": "HIGH",
+            },
+            "status": "TO_REVIEW",
+            "textRange": Object {
+              "endLine": 142,
+              "endOffset": 83,
+              "startLine": 142,
+              "startOffset": 26,
+            },
+            "updateDate": "2013-05-13T17:55:42+0200",
+            "users": Array [
+              Object {
+                "active": true,
+                "local": true,
+                "login": "assignee",
+                "name": "John Doe",
+              },
+              Object {
+                "active": true,
+                "local": true,
+                "login": "author",
+                "name": "John Doe",
+              },
+            ],
+          }
+        }
         onSubmit={[Function]}
       />
     </DropdownOverlay>
@@ -98,7 +389,7 @@ exports[`should register an eventlistener: Dropdown still open 1`] = `
 
 exports[`should render correctly 1`] = `
 <div
-  className="dropdown"
+  className="dropdown big-spacer-left flex-0"
 >
   <Button
     onClick={[Function]}
index 68074754ad72ce5f2c995c62a203f7db20bf38e5..721aace521de0b0fb87ed7cc16def9c49b19b046 100644 (file)
@@ -3,7 +3,7 @@
 exports[`should render correctly 1`] = `
 <HotspotActionsFormRenderer
   comment=""
-  hotspotKey="key"
+  hotspotStatus="REVIEWED"
   onAssign={[Function]}
   onChangeComment={[Function]}
   onSelectOption={[Function]}
index 4ecad39a845259f3922834fa453411b025913435..9264fff96e1c115cb1e67f9888780d7af7413b60 100644 (file)
@@ -90,7 +90,7 @@ exports[`should render correctly 1`] = `
     <SubmitButton
       disabled={false}
     >
-      hotspots.form.submit
+      hotspots.form.submit.TO_REVIEW
     </SubmitButton>
   </div>
 </form>
@@ -189,7 +189,7 @@ exports[`should render correctly: Submitting 1`] = `
     <SubmitButton
       disabled={true}
     >
-      hotspots.form.submit
+      hotspots.form.submit.TO_REVIEW
     </SubmitButton>
   </div>
 </form>
@@ -285,7 +285,7 @@ exports[`should render correctly: safe option selected 1`] = `
     <SubmitButton
       disabled={false}
     >
-      hotspots.form.submit
+      hotspots.form.submit.TO_REVIEW
     </SubmitButton>
   </div>
 </form>
@@ -391,7 +391,7 @@ exports[`should render correctly: user selected 1`] = `
     <SubmitButton
       disabled={false}
     >
-      hotspots.form.submit
+      hotspots.form.submit.TO_REVIEW
     </SubmitButton>
   </div>
 </form>
index e6869dff68ef036c33bdd6d9e19ce7b3236218f3..1c3cebe18870aacb72dec60d3bce6c4c6ba090e5 100644 (file)
@@ -84,7 +84,7 @@ export interface Hotspot {
   project: T.Component;
   resolution?: string;
   rule: HotspotRule;
-  status: string;
+  status: HotspotStatus;
   textRange: T.TextRange;
   updateDate: string;
   users: T.UserBase[];
index 66657bf4ba6981c59887a115e5be0262a6a2ce13..cefefbdb327a9e7a533bb404c05b1586b52cafe5 100644 (file)
@@ -688,7 +688,8 @@ hotspots.form.assign_to=Assign to:
 hotspots.form.select_user=Select a user...
 hotspots.form.comment=Comment:
 hotspots.form.comment.placeholder=This status requires justification
-hotspots.form.submit=Apply changes
+hotspots.form.submit.TO_REVIEW=Submit Review
+hotspots.form.submit.REVIEWED=Apply changes
 
 hotspots.status_option.FIXED=Fixed
 hotspots.status_option.FIXED.description=The code has been modified to follow recommended secure coding practices.