From 0d047b28e39eece43138f71501d88626207ebde4 Mon Sep 17 00:00:00 2001
From: VakarisZ <vakarisz@yahoo.com>
Date: Tue, 25 Aug 2020 11:30:12 +0300
Subject: [PATCH] More work and styling of monkey run page components

---
 .../pages/RunMonkeyPage/CommandDisplay.js     | 39 ++++++++++++-------
 .../RunMonkeyPage/LocalManualRunOptions.js    |  8 ++--
 .../pages/RunMonkeyPage/ManualRunOptions.js   | 28 ++++++++-----
 .../ui-components/DropdownSelect.js           |  5 ++-
 .../inline-selection/BackButton.js            | 15 +++++--
 .../inline-selection/InlineSelection.js       |  5 ++-
 .../inline-selection/NextSelectionButton.js   | 23 ++++++++---
 .../monkey_island/cc/ui/src/styles/Main.scss  |  4 +-
 .../styles/components/InlineSelection.scss    |  8 ----
 .../inline-selection/BackButton.scss          | 20 ++++++++++
 .../inline-selection/InlineSelection.scss     | 12 ++++++
 .../inline-selection/NextSelectionButton.scss | 34 ++++++++++++++++
 12 files changed, 152 insertions(+), 49 deletions(-)
 delete mode 100644 monkey/monkey_island/cc/ui/src/styles/components/InlineSelection.scss
 create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/inline-selection/BackButton.scss
 create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/inline-selection/InlineSelection.scss
 create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/inline-selection/NextSelectionButton.scss

diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js
index bf0852c59..b237e25d2 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/CommandDisplay.js
@@ -2,42 +2,53 @@ import {Button, Card, Nav} from 'react-bootstrap';
 import CopyToClipboard from 'react-copy-to-clipboard';
 import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
 import {faClipboard} from '@fortawesome/free-solid-svg-icons/faClipboard';
-import React, {useState} from 'react';
+import React, {useEffect, useState} from 'react';
 import PropTypes from 'prop-types';
 
 export default function commandDisplay(props) {
 
-  const [selectedVariant, setSelectedVariant] = useState(props.commands[0].name);
+  const [selectedCommand, setSelectedCommand] = useState(props.commands[0]);
+
+  function setSelectedCommandByName(type){
+    setSelectedCommand(getCommandByName(props.commands, type));
+  }
+
+  function getCommandByName(commands, type){
+    return commands.find((command) => {return command.type === type});
+  }
+
+  useEffect(() => {
+    let sameTypeCommand = getCommandByName(props.commands, selectedCommand.type);
+    if( sameTypeCommand !== undefined){
+      setSelectedCommand(sameTypeCommand);
+    } else {
+      setSelectedCommand(props.commands[0]);
+    }
+  }, [props.commands]);
 
   function renderNav() {
     return (
-      <Nav variant='pills' fill activeKey={selectedVariant} onSelect={setSelectedVariant}>
+      <Nav variant='pills' fill activeKey={selectedCommand.type} onSelect={setSelectedCommandByName}>
         {props.commands.map(command => {
           return (
-            <Nav.Item key={command.name}>
-              <Nav.Link eventKey={command.name}>{command.name}</Nav.Link>
+            <Nav.Item key={command.type}>
+              <Nav.Link eventKey={command.type}>{command.type}</Nav.Link>
             </Nav.Item>);
         })}
       </Nav>);
   }
 
-  function getCommandByName(name, commands) {
-    commands.forEach((command) => {
-
-    })
-  }
-
   return (
     <>
       {renderNav()}
       <Card style={{'margin': '0.5em'}}>
         <div style={{'overflow': 'auto', 'padding': '0.5em'}}>
-          <CopyToClipboard text={props.commands[0].name} className="pull-right btn-sm">
+          <CopyToClipboard text={selectedCommand.type} className="pull-right btn-sm">
             <Button style={{margin: '-0.5em'}} title="Copy to Clipboard">
               <FontAwesomeIcon icon={faClipboard}/>
             </Button>
           </CopyToClipboard>
-          <code>{props.commands[0].command}</code>
+          <code>{selectedCommand.command}</code>
         </div>
       </Card>
     </>
@@ -46,7 +57,7 @@ export default function commandDisplay(props) {
 
 commandDisplay.propTypes = {
   commands: PropTypes.arrayOf(PropTypes.exact({
-    name: PropTypes.string,
+    type: PropTypes.string,
     command: PropTypes.string
   }))
 }
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js
index 9680cfbad..9b6783e1b 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/LocalManualRunOptions.js
@@ -37,11 +37,11 @@ const getContents = (props) => {
 
   function generateCommands() {
     if(osType === OS_TYPES.WINDOWS_64 || osType === OS_TYPES.WINDOWS_32) {
-      return [{name: 'CMD', command: GenerateLocalWindowsCmd(selectedIp, osType)},
-              {name: 'Powershell', command: GenerateLocalWindowsPowershell(selectedIp, osType)}]
+      return [{type: 'CMD', command: GenerateLocalWindowsCmd(selectedIp, osType)},
+              {type: 'Powershell', command: GenerateLocalWindowsPowershell(selectedIp, osType)}]
     } else {
-      return [{name: 'CURL', command: GenerateLocalLinuxCurl(selectedIp, osType)},
-              {name: 'WGET', command: GenerateLocalLinuxWget(selectedIp, osType)}]
+      return [{type: 'CURL', command: GenerateLocalLinuxCurl(selectedIp, osType)},
+              {type: 'WGET', command: GenerateLocalLinuxWget(selectedIp, osType)}]
     }
   }
 
diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js
index 6874fc2c8..c82fdbebd 100644
--- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js
+++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js
@@ -3,6 +3,10 @@ import NextSelectionButton from '../../ui-components/inline-selection/NextSelect
 import LocalManualRunOptions from './LocalManualRunOptions';
 import AuthComponent from '../../AuthComponent';
 import BackButton from '../../ui-components/inline-selection/BackButton';
+import {faLaptopCode} from '@fortawesome/free-solid-svg-icons/faLaptopCode';
+import {faNetworkWired} from '@fortawesome/free-solid-svg-icons/faNetworkWired';
+import {faCogs} from '@fortawesome/free-solid-svg-icons/faCogs';
+import {Container} from 'react-bootstrap';
 
 function ManualRunOptions(props) {
 
@@ -41,16 +45,22 @@ function ManualRunOptions(props) {
 
   function getDefaultContents() {
     return (
-      <div className={`container inline-selection-component`}>
-        <NextSelectionButton text={'Local'} onButtonClick={() => {
-          setComponent(LocalManualRunOptions, {ips: ips, setComponent: setComponent})
-        }}/>
-        <NextSelectionButton text={'Remote'} onButtonClick={() => {
-        }}/>
-        <NextSelectionButton text={'Automation'} onButtonClick={() => {
-        }}/>
+      <Container className={'inline-selection-component'}>
+        <NextSelectionButton text={'Local'}
+                             description={'Run on a machine via command.'}
+                             icon={faLaptopCode}
+                             onButtonClick={() => {setComponent(LocalManualRunOptions,
+                                                          {ips: ips, setComponent: setComponent})}}/>
+        <NextSelectionButton text={'Remote'}
+                             description={'Run using remote command execution.'}
+                             icon={faNetworkWired}
+                             onButtonClick={() => {}}/>
+        <NextSelectionButton text={'Automation'}
+                             description={'Run using automation tools like ansible or chef.'}
+                             icon={faCogs}
+                             onButtonClick={() => {}}/>
         <BackButton onClick={props.disableManualOptions} />
-      </div>
+      </Container>
     );
   }
 
diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js b/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js
index d57f14fe4..f7426fb4f 100644
--- a/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js
+++ b/monkey/monkey_island/cc/ui/src/components/ui-components/DropdownSelect.js
@@ -11,7 +11,7 @@ export default function DropdownSelect(props) {
     } else if (typeof data === 'object') {
       return generateDropdownItemsFromObject(data);
     } else {
-      throw "Component can only generate dropdown intems from lists and objects."
+      throw 'Component can only generate dropdown items from arrays and objects.'
     }
   }
 
@@ -35,7 +35,8 @@ export default function DropdownSelect(props) {
     return (
       <Dropdown.Item onClick={() => { setSelectedOption(key);
                                       props.onClick(key)}}
-                     active={(key === selectedOption)}>
+                     active={(key === selectedOption)}
+                     key={value}>
         {value}
       </Dropdown.Item>);
   }
diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/BackButton.js b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/BackButton.js
index eeec63c06..6f2e07bfd 100644
--- a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/BackButton.js
+++ b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/BackButton.js
@@ -1,12 +1,19 @@
-import {Button} from 'react-bootstrap';
+import {Button, Col, Row} from 'react-bootstrap';
 import React from 'react';
 import PropTypes from 'prop-types';
+import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
+import {faCaretLeft} from '@fortawesome/free-solid-svg-icons/faCaretLeft';
 
 export default function backButton(props) {
   return (
-    <Button variant={'secondary'} onClick={props.onClick}>
-      Back
-    </Button>
+    <Row>
+      <Col lg={8} md={10} sm={12}>
+        <Button variant={'outline-dark'} onClick={props.onClick} className={'back-button'}>
+          <FontAwesomeIcon icon={faCaretLeft} />
+          <h1>Back</h1>
+        </Button>
+      </Col>
+    </Row>
   )
 }
 
diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/InlineSelection.js b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/InlineSelection.js
index 2a6dbc897..aa68d0b4e 100644
--- a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/InlineSelection.js
+++ b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/InlineSelection.js
@@ -2,15 +2,16 @@ import React from 'react';
 import PropTypes from 'prop-types';
 import BackButton from './BackButton';
 import ManualRunOptions from '../../pages/RunMonkeyPage/ManualRunOptions';
+import Container from 'react-bootstrap';
 
 
 export default function InlineSelection(WrappedComponent, props, previousComponent){
   return (
-    <div className={`container inline-selection-component`}>
+    <Container className={'inline-selection-component'}>
       {previousComponent === undefined ? '' :
         <BackButton onClick={() => {setPreviousComponent(props, previousComponent)}}/>}
       <WrappedComponent {...props}/>
-    </div>
+    </Container>
   )
 }
 
diff --git a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/NextSelectionButton.js b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/NextSelectionButton.js
index 6f6ac4cb7..41bd3fb55 100644
--- a/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/NextSelectionButton.js
+++ b/monkey/monkey_island/cc/ui/src/components/ui-components/inline-selection/NextSelectionButton.js
@@ -1,17 +1,30 @@
-import {Button} from 'react-bootstrap';
+import {Button, Row, Col} from 'react-bootstrap';
 import React from 'react';
 import PropTypes from 'prop-types';
+import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
+import {faAngleRight} from '@fortawesome/free-solid-svg-icons';
 
 export default function nextSelectionButton(props) {
+  let description = props.description !== undefined ? (<p>{props.description}</p>) : ''
+  let icon = props.icon !== undefined ? (<FontAwesomeIcon icon={props.icon}/>) : ''
   return (
-    <Button variant={'outline-monkey'} size='lg' className={'selection-button'}
-            onClick={props.onButtonClick}>
-      {props.text}
-    </Button>
+    <Row>
+      <Col lg={8} md={10} sm={12}>
+        <Button variant={'outline-monkey'} size='lg' className={'selection-button'}
+                onClick={props.onButtonClick}>
+          {icon}
+          <h1>{props.text}</h1>
+          {description}
+          <FontAwesomeIcon icon={faAngleRight} className={'angle-right'}/>
+        </Button>
+      </Col>
+    </Row>
   )
 }
 
 nextSelectionButton.propTypes = {
   text: PropTypes.string,
+  description: PropTypes.string,
+  icon: FontAwesomeIcon,
   onButtonClick: PropTypes.func
 }
diff --git a/monkey/monkey_island/cc/ui/src/styles/Main.scss b/monkey/monkey_island/cc/ui/src/styles/Main.scss
index 2fb672693..a247b001f 100644
--- a/monkey/monkey_island/cc/ui/src/styles/Main.scss
+++ b/monkey/monkey_island/cc/ui/src/styles/Main.scss
@@ -11,7 +11,9 @@
 @import 'components/InfoPane';
 @import 'components/PreviewPane';
 @import 'components/AdvancedMultiSelect';
-@import 'components/InlineSelection';
+@import 'components/inline-selection/InlineSelection';
+@import 'components/inline-selection/NextSelectionButton';
+@import 'components/inline-selection/BackButton';
 
 
 // Define custom elements after bootstrap import
diff --git a/monkey/monkey_island/cc/ui/src/styles/components/InlineSelection.scss b/monkey/monkey_island/cc/ui/src/styles/components/InlineSelection.scss
deleted file mode 100644
index c264344de..000000000
--- a/monkey/monkey_island/cc/ui/src/styles/components/InlineSelection.scss
+++ /dev/null
@@ -1,8 +0,0 @@
-.inline-selection-component.container {
-  display: flex;
-  justify-content: center;
-}
-
-.inline-selection-component.container .selection-button{
-  margin: 0 5px 0 5px;
-}
diff --git a/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/BackButton.scss b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/BackButton.scss
new file mode 100644
index 000000000..02c5c409e
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/BackButton.scss
@@ -0,0 +1,20 @@
+.inline-selection-component .back-button {
+  width: 100%;
+  text-align: left;
+}
+
+.inline-selection-component .back-button h1{
+  font-size: 1.3em;
+  margin-top: 5px;
+  margin-bottom: 5px;
+  text-align: left;
+  display: inline-block;
+}
+
+.inline-selection-component .back-button svg{
+  font-size: 1.5em;
+  display: inline-block;
+  margin-right: 10px;
+  position: relative;
+  top: 1px;
+}
diff --git a/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/InlineSelection.scss b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/InlineSelection.scss
new file mode 100644
index 000000000..0deda70db
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/InlineSelection.scss
@@ -0,0 +1,12 @@
+//.inline-selection-component.container {
+//  display: flex;
+//  justify-content: center;
+//}
+//
+//.inline-selection-component.container .selection-button{
+//  margin: 0 5px 0 5px;
+//}
+
+.inline-selection-component .selection-button {
+  width: 100%;
+}
diff --git a/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/NextSelectionButton.scss b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/NextSelectionButton.scss
new file mode 100644
index 000000000..71bac3053
--- /dev/null
+++ b/monkey/monkey_island/cc/ui/src/styles/components/inline-selection/NextSelectionButton.scss
@@ -0,0 +1,34 @@
+.inline-selection-component .selection-button {
+  width: 100%;
+  text-align: left;
+  margin-bottom: 20px;
+  padding-right: 40px;
+}
+
+.inline-selection-component .selection-button svg,
+.inline-selection-component .selection-button h1 {
+  display: inline-block;
+}
+
+.inline-selection-component .selection-button h1 {
+  margin: 0;
+  font-size: 1.3em;
+}
+
+.inline-selection-component .selection-button p {
+  margin: 0;
+  font-size: 0.8em;
+}
+
+.inline-selection-component .selection-button svg {
+  margin-bottom: 1px;
+  margin-right: 7px;
+}
+
+.inline-selection-component .selection-button .angle-right {
+  display: inline-block;
+  position: absolute;
+  right: 23px;
+  top: 22%;
+  font-size: 1.7em;
+}