From c4f4a8ef95f9f3d586e261b1f3480874aaf78b3f Mon Sep 17 00:00:00 2001 From: VakarisZ Date: Fri, 18 Sep 2020 15:11:26 +0300 Subject: [PATCH] Refactored UI of run monkey page --- .../RunMonkeyPage/LocalManualRunOptions.js | 1 - .../pages/RunMonkeyPage/RemoteRunOptions.js | 30 -- .../pages/RunMonkeyPage/RunMonkeyPage.js | 339 +------------ .../pages/RunMonkeyPage/RunMonkeyPage2.js | 472 ------------------ .../pages/RunMonkeyPage/RunOnIslandButton.js | 113 +++++ .../{ManualRunOptions.js => RunOptions.js} | 26 +- .../inline-selection/InlineSelection.js | 2 +- .../inline-selection/NextSelectionButton.js | 5 +- .../monkey_island/cc/ui/src/styles/Main.scss | 1 + .../cc/ui/src/styles/components/Icons.scss | 13 + .../styles/components/RunOnIslandButton.scss | 7 + 11 files changed, 150 insertions(+), 859 deletions(-) delete mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RemoteRunOptions.js delete mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js create mode 100644 monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnIslandButton.js rename monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/{ManualRunOptions.js => RunOptions.js} (66%) create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/Icons.scss create mode 100644 monkey/monkey_island/cc/ui/src/styles/components/RunOnIslandButton.scss 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 d5fe77558..0ea045d87 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 @@ -1,6 +1,5 @@ import React, {useEffect, useState} from 'react'; import InlineSelection from '../../ui-components/inline-selection/InlineSelection'; -import ManualRunOptions from './ManualRunOptions'; import DropdownSelect from '../../ui-components/DropdownSelect'; import {OS_TYPES} from './OsTypes'; import GenerateLocalWindowsCmd from './commands/local_windows_cmd'; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RemoteRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RemoteRunOptions.js deleted file mode 100644 index e1731aba4..000000000 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RemoteRunOptions.js +++ /dev/null @@ -1,30 +0,0 @@ -import React, {useEffect, useState} from 'react'; -import NextSelectionButton from '../../ui-components/inline-selection/NextSelectionButton'; -import LocalManualRunOptions from './LocalManualRunOptions'; -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 InlineSelection from '../../ui-components/inline-selection/InlineSelection'; -import ManualRunOptions from './ManualRunOptions'; - - -const RemoteRunOptions = (props) => { - return InlineSelection(getContents, props) -} - -function getContents() { - return ( - <> - { - setComponent(LocalManualRunOptions, - {ips: ips, setComponent: setComponent}) - }}/> - - ); -} - - -export default ManualRunOptions; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage.js index 1a01ac913..2a27c5be3 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage.js @@ -1,288 +1,12 @@ import React from 'react'; -import {css} from '@emotion/core'; -import {Button, Col, Card, Nav, Collapse, Row} from 'react-bootstrap'; -import GridLoader from 'react-spinners/GridLoader'; - -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; -import {faSync} from '@fortawesome/free-solid-svg-icons/faSync'; -import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle'; -import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons/faExclamationTriangle'; - +import {Col} from 'react-bootstrap'; import {Link} from 'react-router-dom'; import AuthComponent from '../../AuthComponent'; -import AwsRunTable from '../../run-monkey/AwsRunTable'; +import RunOptions from './RunOptions'; -import MissingBinariesModal from '../../ui-components/MissingBinariesModal'; -import ManualRunOptions from './ManualRunOptions'; -import Emoji from '../../ui-components/Emoji'; - -const loading_css_override = css` - display: block; - margin-right: auto; - margin-left: auto; -`; class RunMonkeyPageComponent extends AuthComponent { - constructor(props) { - super(props); - this.state = { - runningOnIslandState: 'not_running', - runningOnClientState: 'not_running', - awsClicked: false, - showManual: false, - showAws: false, - isOnAws: false, - awsUpdateClicked: false, - awsUpdateFailed: false, - awsMachines: [], - isLoadingAws: true, - isErrorWhileCollectingAwsMachines: false, - awsMachineCollectionErrorMsg: '', - showModal: false, - errorDetails: '' - }; - - this.closeModal = this.closeModal.bind(this); - } - - componentDidMount() { - this.authFetch('/api/local-monkey') - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({runningOnIslandState: 'running'}); - } else { - this.setState({runningOnIslandState: 'not_running'}); - } - }); - - this.fetchAwsInfo(); - this.fetchConfig(); - - this.authFetch('/api/client-monkey') - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({runningOnClientState: 'running'}); - } else { - this.setState({runningOnClientState: 'not_running'}); - } - }); - - this.props.onStatusChange(); - } - - fetchAwsInfo() { - return this.authFetch('/api/remote-monkey?action=list_aws') - .then(res => res.json()) - .then(res => { - let is_aws = res['is_aws']; - if (is_aws) { - // On AWS! - // Checks if there was an error while collecting the aws machines. - let is_error_while_collecting_aws_machines = (res['error'] != null); - if (is_error_while_collecting_aws_machines) { - // There was an error. Finish loading, and display error message. - this.setState({ - isOnAws: true, - isErrorWhileCollectingAwsMachines: true, - awsMachineCollectionErrorMsg: res['error'], - isLoadingAws: false - }); - } else { - // No error! Finish loading and display machines for user - this.setState({isOnAws: true, awsMachines: res['instances'], isLoadingAws: false}); - } - } else { - // Not on AWS. Finish loading and don't display the AWS div. - this.setState({isOnAws: false, isLoadingAws: false}); - } - }); - } - - runIslandMonkey = () => { - this.authFetch('/api/local-monkey', - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({action: 'run'}) - }) - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({ - runningOnIslandState: 'installing' - }); - } else { - /* If Monkey binaries are missing, change the state accordingly */ - if (res['error_text'].startsWith('Copy file failed')) { - this.setState({ - showModal: true, - errorDetails: res['error_text'] - } - ); - } - this.setState({ - runningOnIslandState: 'not_running' - }); - } - - this.props.onStatusChange(); - }); - }; - - static renderIconByState(state) { - if (state === 'running') { - return () - } else if (state === 'installing') { - return () - } else { - return ''; - } - } - - toggleManual = () => { - this.setState({ - showManual: !this.state.showManual - }); - }; - - toggleAws = () => { - this.setState({ - showAws: !this.state.showAws - }); - }; - - runOnAws = () => { - this.setState({ - awsClicked: true - }); - - let instances = this.awsTable.state.selection.map(x => this.instanceIdToInstance(x)); - - this.authFetch('/api/remote-monkey', - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({type: 'aws', instances: instances, island_ip: this.state.selectedIp}) - }).then(res => res.json()) - .then(res => { - let result = res['result']; - - // update existing state, not run-over - let prevRes = this.awsTable.state.result; - for (let key in result) { - if (result.hasOwnProperty(key)) { - prevRes[key] = result[key]; - } - } - this.awsTable.setState({ - result: prevRes, - selection: [], - selectAll: false - }); - - this.setState({ - awsClicked: false - }); - }); - }; - - fetchConfig() { - return this.authFetch('/api/configuration/island') - .then(res => res.json()) - .then(res => { - return res.configuration; - }) - } - - instanceIdToInstance = (instance_id) => { - let instance = this.state.awsMachines.find( - function (inst) { - return inst['instance_id'] === instance_id; - }); - return {'instance_id': instance_id, 'os': instance['os']} - - }; - - renderAwsMachinesDiv() { - return ( -
-
-

- - Not sure what this is? Not seeing your AWS EC2 instances? Read the documentation! -

-
- - (this.awsTable = r)} - /> -
- -
-
- ) - } - - closeModal = () => { - this.setState({ - showModal: false - }) - }; - - renderIslandVsManual = () => { - return ( - <> -

- - -

-

- OR -

-

- -

-

- Go ahead and monitor the ongoing infection in the Infection Map view. -

- - ) - } - - disableManualOptions = () => { - this.setState({showManual: false}) - } - render() { return ( (Or configure the monkey to fine tune its behavior)

- {this.state.showManual ? - : - this.renderIslandVsManual()} - { - this.state.isLoadingAws ? -
-
- -
-
- : null - } - { - this.state.isOnAws ? -

- OR -

- : - null - } - { - this.state.isOnAws ? -

- -

- : - null - } - - { - this.state.isErrorWhileCollectingAwsMachines ? -
-

- - Error while collecting AWS machine data. Error - message: {this.state.awsMachineCollectionErrorMsg}
- Are you sure you've set the correct role on your Island AWS machine?
- Not sure what this is? Read - the documentation! -

-
- : - this.renderAwsMachinesDiv() - } - -
+ ); } diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js deleted file mode 100644 index 8edd0e44e..000000000 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunMonkeyPage2.js +++ /dev/null @@ -1,472 +0,0 @@ -import React from 'react'; -import {css} from '@emotion/core'; -import {Button, Col, Card, Nav, Collapse, Row} from 'react-bootstrap'; -import CopyToClipboard from 'react-copy-to-clipboard'; -import GridLoader from 'react-spinners/GridLoader'; - -import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; -import {faClipboard} from '@fortawesome/free-solid-svg-icons/faClipboard'; -import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; -import {faSync} from '@fortawesome/free-solid-svg-icons/faSync'; -import {faInfoCircle} from '@fortawesome/free-solid-svg-icons/faInfoCircle'; -import {faExclamationTriangle} from '@fortawesome/free-solid-svg-icons/faExclamationTriangle'; - -import {Link} from 'react-router-dom'; -import AuthComponent from '../../AuthComponent'; -import AwsRunTable from '../../run-monkey/AwsRunTable'; - -import MissingBinariesModal from '../../ui-components/MissingBinariesModal'; -import ManualRunOptions from './ManualRunOptions'; -import Emoji from '../../ui-components/Emoji'; - -const loading_css_override = css` - display: block; - margin-right: auto; - margin-left: auto; -`; - -class RunMonkeyPageComponent2 extends AuthComponent { - - constructor(props) { - super(props); - this.state = { - ips: [], - runningOnIslandState: 'not_running', - runningOnClientState: 'not_running', - awsClicked: false, - selectedIp: '0.0.0.0', - selectedOs: 'windows-32', - showManual: false, - showAws: false, - isOnAws: false, - awsUpdateClicked: false, - awsUpdateFailed: false, - awsMachines: [], - isLoadingAws: true, - isErrorWhileCollectingAwsMachines: false, - awsMachineCollectionErrorMsg: '', - showModal: false, - errorDetails: '' - }; - - this.closeModal = this.closeModal.bind(this); - } - - componentDidMount() { - this.authFetch('/api') - .then(res => res.json()) - .then(res => this.setState({ - ips: res['ip_addresses'], - selectedIp: res['ip_addresses'][0] - })); - - this.authFetch('/api/local-monkey') - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({runningOnIslandState: 'running'}); - } else { - this.setState({runningOnIslandState: 'not_running'}); - } - }); - - this.fetchAwsInfo(); - this.fetchConfig(); - - this.authFetch('/api/client-monkey') - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({runningOnClientState: 'running'}); - } else { - this.setState({runningOnClientState: 'not_running'}); - } - }); - - this.props.onStatusChange(); - } - - fetchAwsInfo() { - return this.authFetch('/api/remote-monkey?action=list_aws') - .then(res => res.json()) - .then(res => { - let is_aws = res['is_aws']; - if (is_aws) { - // On AWS! - // Checks if there was an error while collecting the aws machines. - let is_error_while_collecting_aws_machines = (res['error'] != null); - if (is_error_while_collecting_aws_machines) { - // There was an error. Finish loading, and display error message. - this.setState({ - isOnAws: true, - isErrorWhileCollectingAwsMachines: true, - awsMachineCollectionErrorMsg: res['error'], - isLoadingAws: false - }); - } else { - // No error! Finish loading and display machines for user - this.setState({isOnAws: true, awsMachines: res['instances'], isLoadingAws: false}); - } - } else { - // Not on AWS. Finish loading and don't display the AWS div. - this.setState({isOnAws: false, isLoadingAws: false}); - } - }); - } - - static generateLinuxCmd(ip, is32Bit) { - let bitText = is32Bit ? '32' : '64'; - return `wget --no-check-certificate https://${ip}:5000/api/monkey/download/monkey-linux-${bitText}; chmod +x monkey-linux-${bitText}; ./monkey-linux-${bitText} m0nk3y -s ${ip}:5000` - } - - static generateWindowsCmd(ip, is32Bit) { - let bitText = is32Bit ? '32' : '64'; - return `powershell [System.Net.ServicePointManager]::ServerCertificateValidationCallback = {$true}; (New-Object System.Net.WebClient).DownloadFile('https://${ip}:5000/api/monkey/download/monkey-windows-${bitText}.exe','.\\monkey.exe'); ;Start-Process -FilePath '.\\monkey.exe' -ArgumentList 'm0nk3y -s ${ip}:5000';`; - } - - runLocalMonkey = () => { - this.authFetch('/api/local-monkey', - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({action: 'run'}) - }) - .then(res => res.json()) - .then(res => { - if (res['is_running']) { - this.setState({ - runningOnIslandState: 'installing' - }); - } else { - /* If Monkey binaries are missing, change the state accordingly */ - if (res['error_text'].startsWith('Copy file failed')) { - this.setState({ - showModal: true, - errorDetails: res['error_text'] - } - ); - } - this.setState({ - runningOnIslandState: 'not_running' - }); - } - - this.props.onStatusChange(); - }); - }; - - generateCmdDiv() { - let isLinux = (this.state.selectedOs.split('-')[0] === 'linux'); - let is32Bit = (this.state.selectedOs.split('-')[1] === '32'); - let cmdText = ''; - if (isLinux) { - cmdText = RunMonkeyPageComponent2.generateLinuxCmd(this.state.selectedIp, is32Bit); - } else { - cmdText = RunMonkeyPageComponent2.generateWindowsCmd(this.state.selectedIp, is32Bit); - } - return ( - -
- - - - {cmdText} -
-
- ) - } - - setSelectedOs = (key) => { - this.setState({ - selectedOs: key - }); - }; - - setSelectedIp = (key) => { - this.setState({ - selectedIp: key - }); - }; - - static renderIconByState(state) { - if (state === 'running') { - return () - } else if (state === 'installing') { - return () - } else { - return ''; - } - } - - toggleManual = () => { - this.setState({ - showManual: !this.state.showManual - }); - }; - - toggleAws = () => { - this.setState({ - showAws: !this.state.showAws - }); - }; - - runOnAws = () => { - this.setState({ - awsClicked: true - }); - - let instances = this.awsTable.state.selection.map(x => this.instanceIdToInstance(x)); - - this.authFetch('/api/remote-monkey', - { - method: 'POST', - headers: {'Content-Type': 'application/json'}, - body: JSON.stringify({type: 'aws', instances: instances, island_ip: this.state.selectedIp}) - }).then(res => res.json()) - .then(res => { - let result = res['result']; - - // update existing state, not run-over - let prevRes = this.awsTable.state.result; - for (let key in result) { - if (result.hasOwnProperty(key)) { - prevRes[key] = result[key]; - } - } - this.awsTable.setState({ - result: prevRes, - selection: [], - selectAll: false - }); - - this.setState({ - awsClicked: false - }); - }); - }; - - fetchConfig() { - return this.authFetch('/api/configuration/island') - .then(res => res.json()) - .then(res => { - return res.configuration; - }) - } - - instanceIdToInstance = (instance_id) => { - let instance = this.state.awsMachines.find( - function (inst) { - return inst['instance_id'] === instance_id; - }); - return {'instance_id': instance_id, 'os': instance['os']} - - }; - - renderAwsMachinesDiv() { - return ( -
-
-

- - Not sure what this is? Not seeing your AWS EC2 instances? Read the documentation! -

-
- { - this.state.ips.length > 1 ? - - :
- } - - (this.awsTable = r)} - /> -
- -
-
- ) - } - - closeModal = () => { - this.setState({ - showModal: false - }) - }; - - render() { - return ( - -

1. Run Monkey

-

- Go ahead and run the monkey! - (Or configure the monkey to fine tune its behavior) -

-

- - -

-

- OR -

- -

- -

- -
-

- Choose the operating system where you want to run the monkey: -

- - - - - - - {this.state.ips.length > 1 ? -
- - -

- Choose the interface to communicate with: -

- -
- - - - - -
- :
- } -

- Copy the following command to your machine and run it with Administrator or root privileges. -

- {this.generateCmdDiv()} -
- - { - this.state.isLoadingAws ? -
-
- -
-
- : null - } - { - this.state.isOnAws ? -

- OR -

- : - null - } - { - this.state.isOnAws ? -

- -

- : - null - } - - { - this.state.isErrorWhileCollectingAwsMachines ? -
-

- - Error while collecting AWS machine data. Error - message: {this.state.awsMachineCollectionErrorMsg}
- Are you sure you've set the correct role on your Island AWS machine?
- Not sure what this is? Read - the documentation! -

-
- : - this.renderAwsMachinesDiv() - } - -
- -

- Go ahead and monitor the ongoing infection in the Infection Map view. -

- - ); - } -} - -export default RunMonkeyPageComponent2; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnIslandButton.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnIslandButton.js new file mode 100644 index 000000000..23de0cd21 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOnIslandButton.js @@ -0,0 +1,113 @@ +import React from 'react'; +import {Button, Col, Row} from 'react-bootstrap'; + +import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; +import {faCheck} from '@fortawesome/free-solid-svg-icons/faCheck'; +import {faSync} from '@fortawesome/free-solid-svg-icons/faSync'; +import AuthComponent from '../../AuthComponent'; + +import MissingBinariesModal from '../../ui-components/MissingBinariesModal'; +import '../../../styles/components/RunOnIslandButton.scss'; + + +class RunOnIslandButton extends AuthComponent { + + constructor(props) { + super(props); + this.state = { + runningOnIslandState: 'not_running', + showModal: false, + errorDetails: '' + }; + + this.closeModal = this.closeModal.bind(this); + } + + componentDidMount() { + this.authFetch('/api/local-monkey') + .then(res => res.json()) + .then(res => { + if (res['is_running']) { + this.setState({runningOnIslandState: 'running'}); + } else { + this.setState({runningOnIslandState: 'not_running'}); + } + }); + } + + runIslandMonkey = () => { + this.setState({runningOnIslandState: 'installing'}, this.sendRunMonkeyRequest) + + }; + + sendRunMonkeyRequest = () => { + this.authFetch('/api/local-monkey', + { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({action: 'run'}) + }) + .then(res => res.json()) + .then(res => { + if (res['is_running']) { + this.setState({ + runningOnIslandState: 'running' + }); + } else { + /* If Monkey binaries are missing, change the state accordingly */ + if (res['error_text'].startsWith('Copy file failed')) { + this.setState({ + showModal: true, + errorDetails: res['error_text'] + } + ); + } + this.setState({ + runningOnIslandState: 'not_running' + }); + } + }); + } + + closeModal = () => { + this.setState({ + showModal: false + }) + }; + + getMonkeyRunStateIcon = () => { + if (this.state.runningOnIslandState === 'running') { + return () + } else if (this.state.runningOnIslandState === 'installing') { + return () + } else { + return ''; + } + } + + render() { + let description = this.props.description !== undefined ? (

{this.props.description}

) : '' + let icon = this.props.icon !== undefined ? () : '' + return ( + + + + + + + ); + } +} + +export default RunOnIslandButton; diff --git a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js similarity index 66% rename from monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js rename to monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js index 3dbb97f60..a9fe1f8cf 100644 --- a/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/ManualRunOptions.js +++ b/monkey/monkey_island/cc/ui/src/components/pages/RunMonkeyPage/RunOptions.js @@ -3,13 +3,12 @@ import NextSelectionButton from '../../ui-components/inline-selection/NextSelect import LocalManualRunOptions from './LocalManualRunOptions'; import AuthComponent from '../../AuthComponent'; 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'; import InlineSelection from '../../ui-components/inline-selection/InlineSelection'; import {cloneDeep} from 'lodash'; +import {faExpandArrowsAlt} from '@fortawesome/free-solid-svg-icons'; +import RunOnIslandButton from './RunOnIslandButton'; -function ManualRunOptions(props) { +function RunOptions(props) { const [currentContent, setCurrentContent] = useState(loadingContents()); const [ips, setIps] = useState([]); @@ -45,30 +44,23 @@ function ManualRunOptions(props) { } function getDefaultContents() { - const newProps = cloneDeep({...props, onBackButtonClick: props.disableManualOptions}); + const newProps = cloneDeep({...props}); return InlineSelection(defaultContents, newProps); } function defaultContents() { return ( <> - + { setComponent(LocalManualRunOptions, {ips: ips, setComponent: setComponent}) }}/> - { - }}/> - { - }}/> ); } @@ -76,4 +68,4 @@ function ManualRunOptions(props) { return currentContent; } -export default ManualRunOptions; +export default RunOptions; 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 c7a3d4169..d428c68ee 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 @@ -1,7 +1,7 @@ import React from 'react'; import PropTypes from 'prop-types'; import BackButton from './BackButton'; -import ManualRunOptions from '../../pages/RunMonkeyPage/ManualRunOptions'; +import ManualRunOptions from '../../pages/RunMonkeyPage/RunOptions'; import {Col, Row, Container} from 'react-bootstrap'; 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 433fd076e..7a7c47087 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 @@ -13,7 +13,7 @@ export default function nextSelectionButton(props) { @@ -23,7 +23,8 @@ export default function nextSelectionButton(props) { } nextSelectionButton.propTypes = { - text: PropTypes.string, + title: PropTypes.string, icon: FontAwesomeIcon, + description: PropTypes.string, 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 9ac2d680e..707308031 100644 --- a/monkey/monkey_island/cc/ui/src/styles/Main.scss +++ b/monkey/monkey_island/cc/ui/src/styles/Main.scss @@ -15,6 +15,7 @@ @import 'components/inline-selection/NextSelectionButton'; @import 'components/inline-selection/BackButton'; @import 'components/inline-selection/CommandDisplay'; +@import 'components/Icons'; // Define custom elements after bootstrap import diff --git a/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss b/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss new file mode 100644 index 000000000..ed75d8a9d --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/styles/components/Icons.scss @@ -0,0 +1,13 @@ +.spinning-icon { + animation: spin-animation 0.5s infinite; + display: inline-block; +} + +@keyframes spin-animation { + 0% { + transform: rotate(0deg); + } + 100% { + transform: rotate(359deg); + } +} diff --git a/monkey/monkey_island/cc/ui/src/styles/components/RunOnIslandButton.scss b/monkey/monkey_island/cc/ui/src/styles/components/RunOnIslandButton.scss new file mode 100644 index 000000000..e13c0e8a4 --- /dev/null +++ b/monkey/monkey_island/cc/ui/src/styles/components/RunOnIslandButton.scss @@ -0,0 +1,7 @@ +.monkey-on-island-run-state-icon { + display: inline-block; + position: absolute; + right: 23px; + top: 28%; + font-size: 1.1em; +}