1 import { chainClient } from 'utility/environment'
2 import { connect } from 'react-redux'
3 import componentClassNames from 'utility/componentClassNames'
4 import { PageContent, ErrorBanner, PageTitle } from 'features/shared/components'
5 import React from 'react'
6 import styles from './CoreIndex.scss'
7 import testnetUtils from 'features/testnet/utils'
8 import { docsRoot } from 'utility/environment'
9 import actions from 'actions'
12 class CoreIndex extends React.Component {
16 this.deleteClick = this.deleteClick.bind(this)
17 this.handleAdvancedOptionChange = this.handleAdvancedOptionChange.bind(this)
21 const fetchInfo = () => {
22 if(this.refs.requestComponent) {
23 chainClient().config.info().then(resp => {
24 this.setState({requestStatus: resp.data})
28 setInterval(fetchInfo.bind(this), 2 * 1000)
32 if (!window.confirm('Are you sure you want to delete all data on this core?')) {
36 this.setState({deleteDisabled: true})
38 chainClient().config.reset(true).then(() => {
39 // TODO: Use Redux state reset and nav action instead of window.location.
40 // Also, move confirmation message to a bonafide flash div. alert() in a
41 // browser microtask is going away. cf https://www.chromestatus.com/features/5647113010544640
42 setTimeout(function(){
43 window.location.href = '/'
48 deleteDisabled: false,
53 handleAdvancedOptionChange(event) {
54 const target = event.target
56 this.props.showNavAdvanced()
57 window.localStorage.setItem('NavState', 'advance')
59 this.props.hideNavAdvanced()
60 window.localStorage.setItem('NavState', 'normal')
67 testnetBlockchainMismatch,
68 testnetNetworkMismatch,
73 if (this.props.core.generator) {
74 generatorUrl = window.location.origin
75 } else if (onTestnet) {
77 {this.props.core.generatorUrl}
79 <span className='label label-primary'>Chain Testnet</span>
82 generatorUrl = this.props.core.generatorUrl
85 let navState = window.localStorage.getItem('NavState') === 'advance'
88 <div className={[styles.left, styles.col].join(' ')}>
90 <h4>Configuration</h4>
91 <table className={styles.table}>
94 <td className={styles.row_label}>Core type:</td>
95 <td>{this.props.core.coreType}</td>
98 <td className={styles.row_label}>Setup time:</td>
99 <td>{this.props.core.configuredAt}</td>
102 <td className={styles.row_label}>Version:</td>
103 <td><code>{this.props.core.version}</code></td>
106 <td className={styles.row_label}>Language:</td>
107 <td>{this.props.core.lang === 'zh' ? '中文' : 'English'}</td>
110 <td className={styles.row_label}>MockHSM enabled:</td>
111 <td><code>{this.props.core.mockhsm.toString()}</code></td>
114 <td className={styles.row_label}>Localhost auth:</td>
115 <td><code>{this.props.core.localhostAuth.toString()}</code></td>
118 <td className={styles.row_label}>Reset enabled:</td>
119 <td><code>{this.props.core.reset.toString()}</code></td>
122 <td className={styles.row_label}>Non-TLS HTTP requests enabled:</td>
123 <td><code>{this.props.core.httpOk.toString()}</code></td>
126 <td colSpan={2}><hr /></td>
129 <td className={styles.row_label}>Generator URL:</td>
130 <td>{generatorUrl}</td>
132 {onTestnet && !!testnetNextReset &&
134 <td className={styles.row_label}>Next Chain Testnet data reset:</td>
135 <td>{testnetNextReset.toString()}</td>
137 {!this.props.core.generator &&
139 <td className={styles.row_label}>Generator Access Token:</td>
140 <td><code>{this.props.core.generatorAccessToken}</code></td>
143 <td className={styles.row_label}>Blockchain ID:</td>
144 <td><code className={styles.block_hash}>{this.props.core.blockchainId}</code></td>
147 <td colSpan={2}><hr /></td>
150 <td className={styles.row_label}>Advanced: </td>
152 <label className={styles.switch}>
155 onChange={this.handleAdvancedOptionChange}
158 <span className={styles.slider}></span>
170 if (testnetBlockchainMismatch) {
171 testnetErr = 'Chain Testnet has been reset. Please reset your core below.'
172 } else if (testnetNetworkMismatch) {
173 testnetErr = {message: <span>This core is no longer compatible with Chain Testnet. <a href={`${docsRoot}/core/get-started/install`} target='_blank'>Please upgrade Chain Core</a>.</span>}
177 let requestStatusBlock =
178 this.state.requestStatus && (<div className={styles['sub-row']}>
179 <h4>Request status</h4>
180 <table className={styles.table}>
182 {Object.keys(this.state.requestStatus).map(key => (
184 <td className={styles.row_label}> {key}: </td>
185 <td className={styles.row_value}>{ String(this.state.requestStatus[key])}</td>
192 let networkStatusBlock = (
193 <div className={styles.right}>
194 <div ref='requestComponent'>
195 <div className={[styles.top, styles['sub-row']].join(' ')}>
196 <h4>Network status</h4>
197 <table className={styles.table}>
200 <td className={styles.row_label}>Generator block:</td>
201 <td className={styles.row_value}>{this.props.core.generatorBlockHeight}</td>
204 <td className={styles.row_label}>Local block:</td>
205 <td className={styles.row_value}>{this.props.core.blockHeight}</td>
208 <td className={styles.row_label}>Replication lag:</td>
209 <td className={`${styles.replication_lag} ${styles[this.props.core.replicationLagClass]}`}>
210 {this.props.core.replicationLag === null ? '???' : this.props.core.replicationLag}
218 {testnetErr && <ErrorBanner title='Chain Testnet error' error={testnetErr} />}
222 let resetDataBlock = (
223 <div className='row'>
224 <div className='col-sm-6'>
227 {this.props.core.reset ?
230 This will permanently delete all data stored in this core,
231 including blockchain data, accounts, assets, indexes,
235 {this.state.deleteError && <ErrorBanner
236 title='Error resetting data'
237 message={this.state.deleteError.toString()}
241 className='btn btn-danger'
242 onClick={this.deleteClick}
243 disabled={this.state.deleteDisabled}
249 This core is not configured with reset capabilities.
256 <div className={componentClassNames(this, 'flex-container', styles.mainContainer)}>
257 <PageTitle title='Core' />
260 <div className={`${styles.top} ${styles.flex}`}>
271 const mapStateToProps = (state) => ({
273 onTestnet: state.core.onTestnet,
274 testnetBlockchainMismatch: testnetUtils.isBlockchainMismatch(state),
275 testnetNetworkMismatch: testnetUtils.isCrosscoreRpcMismatch(state),
276 testnetNextReset: state.testnet.nextReset,
279 const mapDispatchToProps = (dispatch) => ({
280 showNavAdvanced: () => dispatch(actions.app.showNavAdvanced),
281 hideNavAdvanced: () => dispatch(actions.app.hideNavAdvanced)
284 export default connect(