OSDN Git Service

add the console component in the core page.
authorZhiting Lin <zlin035@uottawa.ca>
Wed, 20 Jun 2018 11:00:37 +0000 (19:00 +0800)
committerZhiting Lin <zlin035@uottawa.ca>
Wed, 20 Jun 2018 11:00:37 +0000 (19:00 +0800)
17 files changed:
src/actions.js
src/features/app/actions.js
src/features/app/components/Modal/Modal.jsx
src/features/app/components/Modal/Modal.scss
src/features/app/components/SecondaryNavigation/SecondaryNavigation.jsx
src/features/console/actions.js [deleted file]
src/features/console/components/ConsolePage.jsx [deleted file]
src/features/console/components/ConsolePage.scss [deleted file]
src/features/console/components/index.js [deleted file]
src/features/console/index.js [deleted file]
src/features/console/routes.js [deleted file]
src/features/core/components/CoreIndex/CoreIndex.jsx
src/features/shared/components/ConsoleSection/ConsoleSection.jsx
src/features/shared/components/ConsoleSection/ConsoleSection.scss
src/features/shared/components/ConsoleSection/command.json
src/routes.js
static/styles/_body.scss

index 3e9923e..9c2906f 100644 (file)
@@ -4,7 +4,6 @@ import { actions as app } from 'features/app'
 import { actions as asset } from 'features/assets'
 import { actions as balance } from 'features/balances'
 import { actions as configuration } from 'features/configuration'
-import { actions as console } from 'features/console'
 import { actions as core } from 'features/core'
 import { actions as mockhsm } from 'features/mockhsm'
 import { actions as testnet } from 'features/testnet'
@@ -20,7 +19,6 @@ const actions = {
   asset,
   balance,
   configuration,
-  console,
   core,
   key: mockhsm,
   testnet,
index 971c2bf..7239c3f 100644 (file)
@@ -1,4 +1,5 @@
 import { push } from 'react-router-redux'
+import { chainClient } from 'utility/environment'
 
 const actions = {
   dismissFlash: (param) => ({type: 'DISMISS_FLASH', param}),
@@ -28,6 +29,9 @@ const actions = {
         dispatch(push('/configuration'))
       }
     }
+  },
+  cmd: (data) => () => {
+    return chainClient().bytomCli.request(data)
   }
 }
 
index 4edf046..d741eae 100644 (file)
@@ -22,16 +22,23 @@ class Modal extends React.Component {
     }
     const cancel = cancelAction ? () => dispatch(cancelAction) : null
     const backdropAction = cancel || accept
+    const boxStyle = this.props.options.box
 
     return(
       <div className={styles.main}>
         <div className={styles.backdrop} onClick={backdropAction}></div>
-        <div className={`${this.props.options.wide && styles.wide} ${styles.content}`}>
+        <div className={`${this.props.options.wide && styles.wide} ${boxStyle? styles.box: styles.content}`}>
+          {
+            boxStyle &&
+              <div className={styles.title}>
+                <p>Console</p>
+                <button className={`btn ${styles.close}`} onClick={accept}>X</button>
+              </div>
+          }
           {body}
-
-          <button className={`btn btn-${this.props.options.danger ? 'danger' : 'primary'} ${styles.accept}`} onClick={accept}>
-            { lang === 'zh' ?  '关闭' : 'OK' }</button>
-          {cancel && <button className={`btn btn-link ${styles.cancel}`} onClick={cancel}>Cancel</button>}
+          {!boxStyle && <button className={`btn btn-${this.props.options.danger ? 'danger' : 'primary'} ${styles.accept}`} onClick={accept}>
+            { lang === 'zh' ?  '关闭' : 'OK' }</button>}
+          {!boxStyle && cancel && <button className={`btn btn-link ${styles.cancel}`} onClick={cancel}>Cancel</button>}
         </div>
       </div>
     )
index f4de5bd..ce1e445 100644 (file)
 .cancel {
   color: $text-color;
 }
+
+.box {
+  background: $background-color;
+  position: absolute;
+  top: 10%;
+  height: 80%;
+}
+
+.title {
+  height: 50px;
+  padding: 10px 30px;
+  border-bottom: 1px solid $border-color;
+  font-size: $font-size-page-title;
+  color: $text-strong-color;
+}
+
+.close {
+  position: absolute;
+  right: 10px;
+  top: 10px;
+}
index 16341ff..6bbc4c0 100644 (file)
@@ -54,13 +54,6 @@ class SecondaryNavigation extends React.Component {
               { lang === 'zh' ?  '备份与恢复' : 'Backup and Restore'}
             </Link>
           </li>
-
-          <li>
-            <Link to='/console' activeClassName={styles.active}>
-              {navIcon('client', styles)}
-              Console
-            </Link>
-          </li>
         </ul>
       </div>
     )
diff --git a/src/features/console/actions.js b/src/features/console/actions.js
deleted file mode 100644 (file)
index 2a2dfe9..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-import { chainClient } from 'utility/environment'
-
-let actions = {
-  request: (data) => () => {
-    return chainClient().bytomCli.request(data)
-  }
-}
-
-export default actions
diff --git a/src/features/console/components/ConsolePage.jsx b/src/features/console/components/ConsolePage.jsx
deleted file mode 100644 (file)
index ad5e328..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-import React from 'react'
-import componentClassNames from 'utility/componentClassNames'
-import {PageContent, PageTitle, ConsoleSection} from 'features/shared/components'
-import styles from './ConsolePage.scss'
-import {connect} from 'react-redux'
-import actions from 'actions'
-
-class ConsolePage extends React.Component {
-  constructor(props) {
-    super(props)
-  }
-
-  render() {
-    const lang = this.props.core.lang
-
-    return (
-      <div className={componentClassNames(this, 'flex-container', styles.mainContainer)}>
-        <PageTitle title={'Console'}/>
-        <PageContent>
-          <ConsoleSection
-            cmd={this.props.cmd}
-          />
-        </PageContent>
-      </div>
-    )
-  }
-}
-
-const mapStateToProps = (state) => ({
-  core: state.core
-})
-
-const mapDispatchToProps = (dispatch) => ({
-  cmd: (data) => dispatch(actions.console.request(data)),
-})
-
-export default connect(
-  mapStateToProps,
-  mapDispatchToProps
-)(ConsolePage)
diff --git a/src/features/console/components/ConsolePage.scss b/src/features/console/components/ConsolePage.scss
deleted file mode 100644 (file)
index b83ce21..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-.page_header h1 {
-  margin-bottom: 0;
-}
-
-.table {
-  margin-bottom: $grid-gutter-width;
-
-  td {
-    vertical-align: top;
-  }
-}
-
-.row_label {
-  padding-right: $grid-gutter-width;
-  text-transform: capitalize;
-  font-weight: 500;
-  white-space: pre;
-}
-
-.row_value {
-  white-space: pre;
-  text-align: right;
-}
-
-.block_hash {
-  display: block;
-  word-wrap: break-word;
-  word-break: break-all;
-}
-
-.flex {
-  display: flex;
-  //overflow:hidden;
-}
-
-.col {
-  display: flex;
-  width: 50%;
-  padding: $grid-gutter-width;
-  h4 {
-    margin-top: 0;
-  }
-}
-
-.sub-row {
-  padding: $grid-gutter-width $grid-gutter-width 0;
-}
-
-.top {
-  border-bottom: 1px solid $border-color;
-}
-
-.left {
-  padding-left: 0;
-  width: 67%;
-}
-
-.right {
-  border-left: 1px solid $border-color;
-  width: 33%;
-}
-
-.replication_lag {
-  display: inline-block;
-  float: right;
-  border-radius: $border-radius-base;
-  color: white;
-  padding: 0 8px;
-  line-height: 1.5;
-  margin-top: 2px;
-  margin-left: -8px;
-}
-
-.green {
-  background: $highlight-secondary;
-}
-
-.yellow {
-  background: $brand-warning;
-}
-
-.red {
-  background: darken($highlight-danger-background, 20%);
-}
-
-.mainContainer {
-  background-color: $background-color;
-}
-
-code {
-  padding-left: 0;
-  font-size: $font-size-code;
-}
-
-.switch {
-  position: relative;
-  display: inline-block;
-  width: 44px;
-  height: 22px;
-
-  /* Hide default HTML checkbox */
-  input {display:none;}
-
-  input:checked + .slider {
-    background-color: $highlight-default;
-  }
-
-  input:focus + .slider {
-    box-shadow: 0 0 1px $highlight-default;
-  }
-
-  input:checked + .slider:before {
-    -webkit-transform: translateX(22px);
-    -ms-transform: translateX(22px);
-    transform: translateX(22px);
-  }
-}
-
-/* The slider */
-.slider {
-  position: absolute;
-  cursor: pointer;
-  top: 0;
-  left: 0;
-  right: 0;
-  bottom: 0;
-  background-color: #ccc;
-  -webkit-transition: .4s;
-  transition: .4s;
-  border-radius: 34px;
-}
-
-.slider:before {
-  position: absolute;
-  content: "";
-  height: 18px;
-  width: 18px;
-  left: 2px;
-  bottom: 2px;
-  background-color: white;
-  -webkit-transition: .4s;
-  transition: .4s;
-  border-radius: 50%;
-}
\ No newline at end of file
diff --git a/src/features/console/components/index.js b/src/features/console/components/index.js
deleted file mode 100644 (file)
index f38d2c3..0000000
+++ /dev/null
@@ -1,5 +0,0 @@
-import ConsolePage from './ConsolePage'
-
-export {
-  ConsolePage
-}
diff --git a/src/features/console/index.js b/src/features/console/index.js
deleted file mode 100644 (file)
index b133bca..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-import actions from './actions'
-import routes from './routes'
-
-export {
-  actions,
-  routes,
-}
diff --git a/src/features/console/routes.js b/src/features/console/routes.js
deleted file mode 100644 (file)
index 705329d..0000000
+++ /dev/null
@@ -1,8 +0,0 @@
-import { RoutingContainer } from 'features/shared/components'
-import { ConsolePage } from './components'
-
-export default {
-  path: 'console',
-  component: RoutingContainer,
-  indexRoute: { component: ConsolePage }
-}
index 7e7a601..b48f7aa 100644 (file)
@@ -1,7 +1,7 @@
 import { connect } from 'react-redux'
 import {DropdownButton, MenuItem} from 'react-bootstrap'
 import componentClassNames from 'utility/componentClassNames'
-import { PageContent, PageTitle } from 'features/shared/components'
+import { PageContent, PageTitle, ConsoleSection } from 'features/shared/components'
 import React from 'react'
 import styles from './CoreIndex.scss'
 import actions from 'actions'
@@ -16,6 +16,7 @@ class CoreIndex extends React.Component {
     this.handleMiningState = this.handleMiningState.bind(this)
     this.handleAdvancedOptionChange = this.handleAdvancedOptionChange.bind(this)
     this.changeBTMamount = this.changeBTMamount.bind(this)
+    this.consolePopup = this.consolePopup.bind(this)
   }
 
   componentDidMount() {
@@ -49,6 +50,15 @@ class CoreIndex extends React.Component {
     }
   }
 
+  consolePopup(e) {
+    e.preventDefault()
+    this.props.showModal(
+      <ConsoleSection
+        cmd={this.props.cmd}
+      />
+    )
+  }
+
   render() {
     let navState = this.props.navAdvancedState === 'advance'
     let miningState = this.props.core.mingStatus
@@ -175,7 +185,14 @@ class CoreIndex extends React.Component {
 
     return (
       <div className={componentClassNames(this, 'flex-container', styles.mainContainer)}>
-        <PageTitle title={lang === 'zh' ? '核心状态' :'Core Status'} />
+        <PageTitle
+          title={lang === 'zh' ? '核心状态' :'Core Status'}
+          actions={[
+            <button className='btn btn-link' onClick={this.consolePopup}>
+              <img src={require('images/console-window.svg')}/>
+            </button>
+          ]}
+        />
 
         <PageContent>
           <div className={`${styles.flex}`}>
@@ -197,7 +214,17 @@ const mapDispatchToProps = (dispatch) => ({
   showNavAdvanced: () => dispatch(actions.app.showNavAdvanced),
   hideNavAdvanced: () => dispatch(actions.app.hideNavAdvanced),
   uptdateBtmAmountUnit: (param) => dispatch(actions.core.updateBTMAmountUnit(param)),
-  updateMiningState: (param) => dispatch(actions.core.updateMiningState(param))
+  updateMiningState: (param) => dispatch(actions.core.updateMiningState(param)),
+  showModal: (body) => dispatch(actions.app.showModal(
+    body,
+    actions.app.hideModal,
+    null,
+    {
+      box: true,
+      wide: true
+    }
+  )),
+  cmd: (data) => dispatch(actions.app.cmd(data))
 })
 
 export default connect(
index e2bee5e..ccc9288 100644 (file)
@@ -10,16 +10,37 @@ class ConsoleSection extends React.Component {
   }
 
   echo (text) {
-    if(text.startsWith('help')){
-      this.terminal.log(command['help'])
+    if(text.trim() === 'help'){
+      command['help'].forEach( (descriptionLine) => {
+        this.terminal.log(descriptionLine)
+      })
+    }else if(text.trim() === 'clear'){
+      this.terminal.setState({
+        acceptInput: true,
+        log: []
+      })
     }else{
       this.props.cmd(text)
         .then(data=>
         {
-          this.terminal.log(JSON.stringify(data, null, 2))
+          if(data.status === 'success'){
+            let output = data.data
+            if(output){
+              const keys = Object.keys(output)
+              if(keys.length === 1){
+                this.terminal.log(output[keys[0]])
+              }else{
+                this.terminal.log(JSON.stringify(output, null, 2))
+              }
+            }
+          }else if(data.status === 'fail'){
+            this.terminal.logX('Error', data.msg.replace(/"/g,''))
+          }else{
+            this.terminal.log(JSON.stringify(data.data, null, 2))
+          }
         }).catch(() =>
         {
-          this.terminal.log('command not found')
+          this.terminal.logX('Error','command not found')
         })
     }
     this.terminal.return()
@@ -27,24 +48,22 @@ class ConsoleSection extends React.Component {
 
   render() {
     return(
-      <div className='form-group'>
-        <div
-          className={styles.reactConsoleContainer}
-        >
-          <p>
-            Welcome to the Bytom Core API console.<br/>
-            Type <code>help</code> for an overview of available commands.
-          </p>
-          <p className='text-danger'>
-            <strong>WARNING:</strong> Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.
-          </p>
+      <div
+        className={styles.reactConsoleContainer}
+      >
+        <p>
+          Welcome to the Bytom Core API console.<br/>
+          Type <code>help</code> for an overview of available commands.
+        </p>
+        <p className='text-danger'>
+          <strong>WARNING:</strong> Scammers have been active, telling users to type commands here, stealing their wallet contents. Do not use this console without fully understanding the ramification of a command.
+        </p>
 
-          <Console
-            ref={ref => this.terminal = ref}
-            handler={this.echo}
-            autofocus={true}
-          />
-        </div>
+        <Console
+          ref={ref => this.terminal = ref}
+          handler={this.echo}
+          autofocus={true}
+        />
       </div>
     )
   }
index 0bcd185..fe2cec1 100644 (file)
@@ -2,5 +2,7 @@
   font-size: 0.85em;
   font-family: "Menlo", "Consolas", "DejaVu Sans Mono", monospace;
   box-sizing: border-box;
-  padding: 0.5em;
+  height: calc( 100% - 50px );
+  padding: 30px;
+  overflow: scroll;
 }
index 1845dca..7e281d2 100644 (file)
@@ -1,3 +1,26 @@
 {
-  "help": "create-key <alias> <password>\nlist-keys"
+  "help": [
+    "validate-address <address>",
+    "sign-message <address> <message> <password>",
+    "get-transaction <transaction id>",
+    "list-transactions",
+    "build-transaction <base_transaction> [{\"account_id\":id,\"amount\":amount,\"asset_id\": id,\"type\":type of transaction}…] <ttl> <time_range>",
+    "sign-transaction <password> <transaction>",
+    "estimate-transaction-gas <transaction>",
+    "get-unconfirmed-transaction <tx_id>",
+    "list-unconfirmed-transactions",
+    "decode-raw-transaction <raw_transaction>",
+    "get-block-count",
+    "get-block-hash",
+    "get-block  ( <block_height> | <block_hash> )",
+    "get-block-header  ( <block_height> | <block_hash> )",
+    "get-difficulty  ( <block_height> | <block_hash> )",
+    "get-hash-rate ( <block_height> | <block_hash> )",
+    "net-info",
+    "is-mining",
+    "set-mining <true|false>",
+    "gas-rate",
+    "verify-message <address> <derived_xpub> <message> <signature>",
+    "decode-program <program>"
+  ]
 }
\ No newline at end of file
index 6260f1b..5d95211 100644 (file)
@@ -11,7 +11,6 @@ import { routes as transactionFeeds } from 'features/transactionFeeds'
 import { routes as unspents } from 'features/unspents'
 import { routes as mockhsm } from 'features/mockhsm'
 import { routes as backup } from 'features/backup'
-import { routes as console } from 'features/console'
 
 const makeRoutes = (store) => ({
   path: '/',
@@ -28,7 +27,6 @@ const makeRoutes = (store) => ({
     unspents(store),
     mockhsm(store),
     backup,
-    console,
     {
       path: '*',
       component: NotFound
index 502a2d7..d093a5f 100644 (file)
@@ -168,6 +168,10 @@ a:focus {
   font-weight: normal;
 }
 
+.text-danger{
+  color: $text-danger;
+}
+
 div.react-console-prompt-box {
   padding-top: 1em;
   color: #444;
@@ -207,10 +211,16 @@ div.react-console-focus span.react-console-cursor-idle {
     background: none;
     color: #444; } }
 
-div.react-console-message {
+div.react-console-message,
+span.react-console-prompt {
   white-space: pre-wrap;      /* CSS3 */
   white-space: -moz-pre-wrap; /* Firefox */
   white-space: -pre-wrap;     /* Opera <7 */
   white-space: -o-pre-wrap;   /* Opera 7 */
   word-wrap: break-word;      /* IE */
-  padding: 0.1em; }
+  padding: 0.1em;
+}
+
+div.react-console-message-Error{
+  color: $text-danger;
+}