7 changed files with 744 additions and 579 deletions
@ -0,0 +1,322 @@ |
|||
import React from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { translate } from '../../../translate/translate'; |
|||
import Config from '../../../config'; |
|||
import { |
|||
iguanaActiveHandle, |
|||
getAppConfig, |
|||
getAppInfo, |
|||
resetAppConfig, |
|||
saveAppConfig, |
|||
skipFullDashboardUpdate, |
|||
triggerToaster, |
|||
} from '../../../actions/actionCreators'; |
|||
import Store from '../../../store'; |
|||
|
|||
class AppSettingsPanel extends React.Component { |
|||
constructor() { |
|||
super(); |
|||
this.state = { |
|||
appSettings: {}, |
|||
appConfigSchema: {}, |
|||
}; |
|||
this._saveAppConfig = this._saveAppConfig.bind(this); |
|||
this._resetAppConfig = this._resetAppConfig.bind(this); |
|||
this._skipFullDashboardUpdate = this._skipFullDashboardUpdate.bind(this); |
|||
this.updateInput = this.updateInput.bind(this); |
|||
} |
|||
|
|||
componentWillMount() { |
|||
try { |
|||
const _appConfigSchema = window.require('electron').remote.getCurrentWindow().appConfigSchema; |
|||
const _appSettings = this.props.Settings.appSettings ? this.props.Settings.appSettings : Object.assign({}, window.require('electron').remote.getCurrentWindow().appConfig); |
|||
|
|||
this.setState(Object.assign({}, this.state, { |
|||
appConfigSchema: _appConfigSchema, |
|||
appSettings: _appSettings, |
|||
})); |
|||
} catch(e) {} |
|||
} |
|||
|
|||
componentDidMount(props) { |
|||
if (!this.props.disableWalletSpecificUI) { |
|||
Store.dispatch(iguanaActiveHandle()); |
|||
} |
|||
|
|||
Store.dispatch(getAppConfig()); |
|||
Store.dispatch(getAppInfo()); |
|||
} |
|||
|
|||
_skipFullDashboardUpdate() { |
|||
Store.dispatch(skipFullDashboardUpdate(!this.props.Dashboard.skipFullDashboardUpdate)); |
|||
} |
|||
|
|||
_resetAppConfig() { |
|||
Store.dispatch(resetAppConfig()); |
|||
} |
|||
|
|||
_saveAppConfig() { |
|||
const _appSettings = this.state.appSettings; |
|||
let _appSettingsPristine = Object.assign({}, this.props.Settings.appSettings); |
|||
let isError = false; |
|||
let saveAfterPathCheck = false; |
|||
|
|||
for (let key in _appSettings) { |
|||
if (key.indexOf('__') === -1) { |
|||
_appSettingsPristine[key] = this.state.appConfigSchema[key] && this.state.appConfigSchema[key].type === 'number' ? Number(_appSettings[key]) : _appSettings[key]; |
|||
|
|||
if (this.state.appConfigSchema[key] && this.state.appConfigSchema[key].type === 'folder' && |
|||
_appSettings[key] && |
|||
_appSettings[key].length) { |
|||
const _testLocation = window.require('electron').remote.getCurrentWindow().testLocation; |
|||
saveAfterPathCheck = true; |
|||
|
|||
_testLocation(_appSettings[key]) |
|||
.then((res) => { |
|||
if (res === -1) { |
|||
isError = true; |
|||
Store.dispatch( |
|||
triggerToaster( |
|||
translate('TOASTR.KOMODO_DATADIR_INVALID'), |
|||
translate('INDEX.SETTINGS'), |
|||
'error' |
|||
) |
|||
); |
|||
} else if (res === false) { |
|||
isError = true; |
|||
Store.dispatch( |
|||
triggerToaster( |
|||
translate('TOASTR.KOMODO_DATADIR_NOT_DIR'), |
|||
translate('INDEX.SETTINGS'), |
|||
'error' |
|||
) |
|||
); |
|||
} else { |
|||
Store.dispatch(saveAppConfig(_appSettingsPristine)); |
|||
} |
|||
}); |
|||
} |
|||
} else { |
|||
const _nestedKey = key.split('__'); |
|||
_appSettingsPristine[_nestedKey[0]][_nestedKey[1]] = this.state.appConfigSchema[_nestedKey[0]][_nestedKey[1]].type === 'number' ? Number(_appSettings[key]) : _appSettings[key]; |
|||
} |
|||
} |
|||
|
|||
if (!saveAfterPathCheck) { |
|||
Store.dispatch(saveAppConfig(_appSettingsPristine)); |
|||
} |
|||
} |
|||
|
|||
|
|||
renderConfigEditForm() { |
|||
let items = []; |
|||
const _appConfig = this.state.appSettings; |
|||
for (let key in _appConfig) { |
|||
if (this.state.appConfigSchema[key] && typeof _appConfig[key] === 'object') { |
|||
if (this.state.appConfigSchema[key].display) { |
|||
items.push( |
|||
<tr key={ `app-settings-${key}` }> |
|||
<td className="padding-15"> |
|||
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key } |
|||
{ this.state.appConfigSchema[key].info && |
|||
<i |
|||
className="icon fa-question-circle settings-help" |
|||
title={ this.state.appConfigSchema[key].info }></i> |
|||
} |
|||
</td> |
|||
<td className="padding-15"></td> |
|||
</tr> |
|||
); |
|||
|
|||
for (let _key in _appConfig[key]) { |
|||
items.push( |
|||
<tr key={ `app-settings-${key}-${_key}` }> |
|||
<td className="padding-15 padding-left-30"> |
|||
{ this.state.appConfigSchema[key][_key].displayName ? this.state.appConfigSchema[key][_key].displayName : _key } |
|||
{ this.state.appConfigSchema[key][_key].info && |
|||
<i |
|||
className="icon fa-question-circle settings-help" |
|||
title={ this.state.appConfigSchema[key][_key].info }></i> |
|||
} |
|||
</td> |
|||
<td className="padding-15"> |
|||
{ this.state.appConfigSchema[key][_key].type === 'number' && |
|||
<input |
|||
type="number" |
|||
pattern="[0-9]*" |
|||
name={ `${key}__${_key}` } |
|||
value={ _appConfig[key][_key] } |
|||
onChange={ (event) => this.updateInputSettings(event, key, _key) } /> |
|||
} |
|||
{ (this.state.appConfigSchema[key][_key].type === 'string' || this.state.appConfigSchema[key][_key].type === 'folder') && |
|||
<input |
|||
type="text" |
|||
name={ `${key}__${_key}` } |
|||
value={ _appConfig[key][_key] } |
|||
className={ this.state.appConfigSchema[key][_key].type === 'folder' ? 'full-width': '' } |
|||
onChange={ (event) => this.updateInputSettings(event, key, _key) } /> |
|||
} |
|||
{ this.state.appConfigSchema[key][_key].type === 'boolean' && |
|||
<span className="pointer toggle"> |
|||
<label className="switch"> |
|||
<input |
|||
type="checkbox" |
|||
name={ `${key}__${_key}` } |
|||
value={ _appConfig[key] } |
|||
checked={ _appConfig[key][_key] } /> |
|||
<div |
|||
className="slider" |
|||
onClick={ (event) => this.updateInputSettings(event, key, _key) }></div> |
|||
</label> |
|||
</span> |
|||
} |
|||
</td> |
|||
</tr> |
|||
); |
|||
} |
|||
} |
|||
} else { |
|||
if (this.state.appConfigSchema[key] && this.state.appConfigSchema[key].display) { |
|||
items.push( |
|||
<tr key={ `app-settings-${key}` }> |
|||
<td className="padding-15"> |
|||
{ this.state.appConfigSchema[key].displayName ? this.state.appConfigSchema[key].displayName : key } |
|||
{ this.state.appConfigSchema[key].info && |
|||
<i |
|||
className="icon fa-question-circle settings-help" |
|||
title={ this.state.appConfigSchema[key].info }></i> |
|||
} |
|||
</td> |
|||
<td className="padding-15"> |
|||
{ this.state.appConfigSchema[key].type === 'number' && |
|||
<input |
|||
type="number" |
|||
pattern="[0-9]*" |
|||
name={ `${key}` } |
|||
value={ _appConfig[key] } |
|||
onChange={ (event) => this.updateInputSettings(event, key) } /> |
|||
} |
|||
{ (this.state.appConfigSchema[key].type === 'string' || this.state.appConfigSchema[key].type === 'folder') && |
|||
<input |
|||
type="text" |
|||
name={ `${key}` } |
|||
value={ _appConfig[key] } |
|||
className={ this.state.appConfigSchema[key].type === 'folder' ? 'full-width': '' } |
|||
onChange={ (event) => this.updateInputSettings(event, key) } /> |
|||
} |
|||
{ this.state.appConfigSchema[key].type === 'boolean' && |
|||
<span className="pointer toggle"> |
|||
<label className="switch"> |
|||
<input |
|||
type="checkbox" |
|||
name={ `${key}` } |
|||
value={ _appConfig[key] } |
|||
checked={ _appConfig[key] } /> |
|||
<div |
|||
className="slider" |
|||
onClick={ (event) => this.updateInputSettings(event, key) }></div> |
|||
</label> |
|||
</span> |
|||
} |
|||
</td> |
|||
</tr> |
|||
); |
|||
} |
|||
} |
|||
} |
|||
|
|||
items.push( |
|||
<tr key={ `kmd-main-sync-only` }> |
|||
<td className="padding-15"> |
|||
KMD main sync only |
|||
<i |
|||
className="icon fa-question-circle settings-help" |
|||
title="Fetch block synchronization data only. Skip any other requests that can deteriorate sync speed."></i> |
|||
</td> |
|||
<td className="padding-15"> |
|||
<span className="pointer toggle"> |
|||
<label className="switch"> |
|||
<input |
|||
type="checkbox" |
|||
name={ `kmd-main-sync-only` } |
|||
value={ this.props.Dashboard.skipFullDashboardUpdate } |
|||
checked={ this.props.Dashboard.skipFullDashboardUpdate } /> |
|||
<div |
|||
className="slider" |
|||
onClick={ this._skipFullDashboardUpdate }></div> |
|||
</label> |
|||
</span> |
|||
</td> |
|||
</tr> |
|||
); |
|||
|
|||
return items; |
|||
} |
|||
|
|||
updateInput(e) { |
|||
this.setState({ |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
} |
|||
|
|||
updateInputSettings(e, parentKey, childKey) { |
|||
let _appSettings = this.state.appSettings; |
|||
let _appSettingsPrev = Object.assign({}, _appSettings); |
|||
|
|||
if (!childKey && this.state.appConfigSchema[parentKey].type === 'boolean') { |
|||
_appSettings[parentKey] = typeof _appSettings[parentKey] !== undefined ? !_appSettings[parentKey] : !this.state.appSettings[parentKey]; |
|||
} else if (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'boolean') { |
|||
_appSettings[parentKey][childKey] = typeof _appSettings[parentKey][childKey] !== undefined ? !_appSettings[parentKey][childKey] : !this.state.appSettings[parentKey][childKey]; |
|||
} else if ((!childKey && this.state.appConfigSchema[parentKey].type === 'number') || (childKey && this.state.appConfigSchema[parentKey][childKey].type === 'number')) { |
|||
if (e.target.value === '') { |
|||
_appSettings[e.target.name] = _appSettingsPrev[e.target.name]; |
|||
} else { |
|||
_appSettings[e.target.name] = e.target.value.replace(/[^0-9]+/g, ''); |
|||
} |
|||
} else { |
|||
_appSettings[e.target.name] = e.target.value; |
|||
} |
|||
|
|||
this.setState({ |
|||
appSettings: _appSettings, |
|||
}); |
|||
} |
|||
|
|||
render() { |
|||
return ( |
|||
<div className="panel-body"> |
|||
<p> |
|||
<strong>{ translate('SETTINGS.CONFIG_RESTART_REQUIRED') }</strong> |
|||
</p> |
|||
<div className="col-sm-12 padding-top-15"> |
|||
<table> |
|||
<tbody> |
|||
{ this.renderConfigEditForm() } |
|||
</tbody> |
|||
</table> |
|||
</div> |
|||
<div className="col-sm-12 col-xs-12 text-align-center padding-top-35 padding-bottom-30"> |
|||
<button |
|||
type="button" |
|||
className="btn btn-primary waves-effect waves-light" |
|||
onClick={ this._saveAppConfig }>{ translate('SETTINGS.SAVE_APP_CONFIG') }</button> |
|||
<button |
|||
type="button" |
|||
className="btn btn-primary waves-effect waves-light margin-left-30" |
|||
onClick={ this._resetAppConfig }>Reset to default</button> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
} |
|||
|
|||
const mapStateToProps = (state) => { |
|||
return { |
|||
Settings: state.Settings, |
|||
Dashboard: { |
|||
skipFullDashboardUpdate: state.Dashboard.skipFullDashboardUpdate, |
|||
} |
|||
}; |
|||
}; |
|||
|
|||
export default connect(mapStateToProps)(AppSettingsPanel); |
@ -0,0 +1,206 @@ |
|||
import React from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { translate } from '../../../translate/translate'; |
|||
import { |
|||
shepherdCli, |
|||
} from '../../../actions/actionCreators'; |
|||
import Store from '../../../store'; |
|||
|
|||
class CliPanel extends React.Component { |
|||
constructor() { |
|||
super(); |
|||
this.state = { |
|||
cliCmdString: '', |
|||
cliCoin: null, |
|||
cliResponse: null, |
|||
}; |
|||
} |
|||
|
|||
renderActiveCoinsList(mode) { |
|||
const modes = [ |
|||
'native', |
|||
'basilisk', |
|||
'full' |
|||
]; |
|||
|
|||
const allCoins = this.props.Main.coins; |
|||
let items = []; |
|||
|
|||
if (allCoins) { |
|||
if (mode === 'all') { |
|||
modes.map(function(mode) { |
|||
allCoins[mode].map(function(coin) { |
|||
items.push( |
|||
<option |
|||
value={ coin } |
|||
key={ coin }> |
|||
{ coin } ({ mode }) |
|||
</option> |
|||
); |
|||
}); |
|||
}); |
|||
} else { |
|||
allCoins[mode].map(function(coin) { |
|||
items.push( |
|||
<option |
|||
value={ coin } |
|||
key={ coin }> |
|||
{ coin } ({ mode }) |
|||
</option> |
|||
); |
|||
}); |
|||
} |
|||
|
|||
return items; |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
// TODO: rerender only if prop is changed
|
|||
renderCliResponse() { |
|||
const _cliResponse = this.props.Settings.cli; |
|||
let _items = []; |
|||
|
|||
if (_cliResponse) { |
|||
let _cliResponseParsed; |
|||
let responseType; |
|||
|
|||
try { |
|||
_cliResponseParsed = JSON.parse(_cliResponse.result); |
|||
} catch(e) { |
|||
_cliResponseParsed = _cliResponse.result; |
|||
} |
|||
|
|||
if (Object.prototype.toString.call(_cliResponseParsed) === '[object Array]') { |
|||
responseType = 'array'; |
|||
|
|||
for (let i = 0; i < _cliResponseParsed.length; i++) { |
|||
_items.push( |
|||
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed[i], null, '\t') }</div> |
|||
); |
|||
} |
|||
} |
|||
if (Object.prototype.toString.call(_cliResponseParsed) === '[object]' || |
|||
typeof _cliResponseParsed === 'object') { |
|||
responseType = 'object'; |
|||
|
|||
_items.push( |
|||
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ JSON.stringify(_cliResponseParsed, null, '\t') }</div> |
|||
); |
|||
} |
|||
if (Object.prototype.toString.call(_cliResponseParsed) === 'number' || |
|||
typeof _cliResponseParsed === 'boolean' || |
|||
_cliResponseParsed === 'wrong cli string format') { |
|||
responseType = 'number'; |
|||
|
|||
_items.push( |
|||
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed.toString() }</div> |
|||
); |
|||
} |
|||
|
|||
if (responseType !== 'number' && |
|||
responseType !== 'array' && |
|||
responseType !== 'object' && |
|||
_cliResponseParsed.indexOf('\n') > -1) { |
|||
_cliResponseParsed = _cliResponseParsed.split('\n'); |
|||
|
|||
for (let i = 0; i < _cliResponseParsed.length; i++) { |
|||
_items.push( |
|||
<div key={ `cli-response-${Math.random(0, 9) * 10}` }>{ _cliResponseParsed[i] }</div> |
|||
); |
|||
} |
|||
} |
|||
|
|||
return ( |
|||
<div> |
|||
<div> |
|||
<strong>{ translate('SETTINGS.CLI_RESPONSE') }:</strong> |
|||
</div> |
|||
{ _items } |
|||
</div> |
|||
); |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
execCliCmd() { |
|||
Store.dispatch( |
|||
shepherdCli( |
|||
'passthru', |
|||
this.state.cliCoin, |
|||
this.state.cliCmdString |
|||
) |
|||
); |
|||
} |
|||
|
|||
updateInput = (e) => { |
|||
this.setState({ |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
} |
|||
|
|||
render() { |
|||
return ( |
|||
<div className="panel-body"> |
|||
<p>{ translate('INDEX.CLI_SELECT_A_COIN') }</p> |
|||
<div className="col-sm-12"></div> |
|||
<form |
|||
className="execute-cli-cmd-form" |
|||
method="post" |
|||
action="javascript:" |
|||
autoComplete="off"> |
|||
<div className="form-group form-material floating"> |
|||
<select |
|||
className="form-control form-material" |
|||
name="cliCoin" |
|||
id="settingsCliOptions" |
|||
onChange={ this.updateInput }> |
|||
<option>{ translate('INDEX.CLI_NATIVE_COIN') }</option> |
|||
{ this.renderActiveCoinsList('native') } |
|||
</select> |
|||
<label |
|||
className="floating-label" |
|||
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.COIN') }</label> |
|||
</div> |
|||
<div className="form-group form-material floating"> |
|||
<textarea |
|||
type="text" |
|||
className="form-control" |
|||
name="cliCmdString" |
|||
id="cliCmd" |
|||
value={ this.state.cliCmdString } |
|||
onChange={ this.updateInput }></textarea> |
|||
<label |
|||
className="floating-label" |
|||
htmlFor="readDebugLogLines">{ translate('INDEX.TYPE_CLI_CMD') }</label> |
|||
</div> |
|||
<div className="col-sm-12 col-xs-12 text-align-center"> |
|||
<button |
|||
type="button" |
|||
className="btn btn-primary waves-effect waves-light" |
|||
disabled={ !this.state.cliCoin || !this.state.cliCmdString } |
|||
onClick={ () => this.execCliCmd() }>{ translate('INDEX.EXECUTE') }</button> |
|||
</div> |
|||
<div className="col-sm-12 col-xs-12 text-align-left"> |
|||
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0"> |
|||
{ this.renderCliResponse() } |
|||
</div> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
); |
|||
}; |
|||
} |
|||
|
|||
const mapStateToProps = (state) => { |
|||
return { |
|||
Main: { |
|||
coins: state.Main.coins, |
|||
}, |
|||
Settings: state.Settings, |
|||
}; |
|||
}; |
|||
|
|||
export default connect(mapStateToProps)(CliPanel); |
@ -0,0 +1,114 @@ |
|||
import React from 'react'; |
|||
import { connect } from 'react-redux'; |
|||
import { translate } from '../../../translate/translate'; |
|||
import Config from '../../../config'; |
|||
import { |
|||
getDebugLog, |
|||
} from '../../../actions/actionCreators'; |
|||
import Store from '../../../store'; |
|||
|
|||
class DebugLogPanel extends React.Component { |
|||
constructor() { |
|||
super(); |
|||
this.state = { |
|||
debugLinesCount: 10, |
|||
debugTarget: 'iguana', |
|||
nativeOnly: Config.iguanaLessMode, |
|||
}; |
|||
this.readDebugLog = this.readDebugLog.bind(this); |
|||
this.updateInput = this.updateInput.bind(this); |
|||
} |
|||
|
|||
readDebugLog() { |
|||
Store.dispatch( |
|||
getDebugLog( |
|||
this.state.debugTarget, |
|||
this.state.debugLinesCount |
|||
) |
|||
); |
|||
} |
|||
|
|||
renderDebugLogData() { |
|||
if (this.props.Settings.debugLog) { |
|||
const _debugLogDataRows = this.props.Settings.debugLog.split('\n'); |
|||
|
|||
if (_debugLogDataRows && |
|||
_debugLogDataRows.length) { |
|||
return _debugLogDataRows.map((_row) => |
|||
<div |
|||
key={ `settings-debuglog-${Math.random(0, 9) * 10}` } |
|||
className="padding-bottom-5">{ _row }</div> |
|||
); |
|||
} else { |
|||
return ( |
|||
<span>{ translate('INDEX.EMPTY_DEBUG_LOG') }</span> |
|||
); |
|||
} |
|||
} else { |
|||
return null; |
|||
} |
|||
} |
|||
|
|||
updateInput(e) { |
|||
this.setState({ |
|||
[e.target.name]: e.target.value, |
|||
}); |
|||
} |
|||
|
|||
render() { |
|||
return ( |
|||
<div className="panel-body"> |
|||
<p>{ translate('INDEX.DEBUG_LOG_DESC') }</p> |
|||
<div className="col-sm-12"></div> |
|||
<form |
|||
className="read-debug-log-import-form" |
|||
method="post" |
|||
action="javascript:" |
|||
autoComplete="off"> |
|||
<div className="form-group form-material floating"> |
|||
<input |
|||
type="text" |
|||
className="form-control" |
|||
name="debugLinesCount" |
|||
id="readDebugLogLines" |
|||
value={ this.state.debugLinesCount } |
|||
onChange={ this.updateInput } /> |
|||
<label |
|||
className="floating-label" |
|||
htmlFor="readDebugLogLines">{ translate('INDEX.DEBUG_LOG_LINES') }</label> |
|||
</div> |
|||
<div className="form-group form-material floating"> |
|||
<select |
|||
className="form-control form-material" |
|||
name="debugTarget" |
|||
id="settingsDelectDebugLogOptions" |
|||
onChange={ this.updateInput }> |
|||
<option value="iguana" className={ this.state.nativeOnly ? 'hide' : '' }>Iguana</option> |
|||
<option value="komodo">Komodo</option> |
|||
</select> |
|||
<label |
|||
className="floating-label" |
|||
htmlFor="settingsDelectDebugLogOptions">{ translate('INDEX.TARGET') }</label> |
|||
</div> |
|||
<div className="col-sm-12 col-xs-12 text-align-center"> |
|||
<button |
|||
type="button" |
|||
className="btn btn-primary waves-effect waves-light" |
|||
onClick={ this.readDebugLog }>{ translate('INDEX.LOAD_DEBUG_LOG') }</button> |
|||
</div> |
|||
<div className="col-sm-12 col-xs-12 text-align-left"> |
|||
<div className="padding-top-40 padding-bottom-20 horizontal-padding-0">{ this.renderDebugLogData() }</div> |
|||
</div> |
|||
</form> |
|||
</div> |
|||
); |
|||
}; |
|||
} |
|||
|
|||
const mapStateToProps = (state) => { |
|||
return { |
|||
Settings: state.Settings |
|||
}; |
|||
}; |
|||
|
|||
export default connect(mapStateToProps)(DebugLogPanel); |
@ -0,0 +1,82 @@ |
|||
import React from 'react'; |
|||
import { translate } from '../../../translate/translate'; |
|||
|
|||
class SupportPanel extends React.Component { |
|||
constructor() { |
|||
super(); |
|||
} |
|||
|
|||
openExternalWindow(url) { |
|||
const remote = window.require('electron').remote; |
|||
const BrowserWindow = remote.BrowserWindow; |
|||
|
|||
const externalWindow = new BrowserWindow({ |
|||
width: 1280, |
|||
height: 800, |
|||
title: `${translate('INDEX.LOADING')}...`, |
|||
icon: remote.getCurrentWindow().iguanaIcon, |
|||
}); |
|||
|
|||
externalWindow.loadURL(url); |
|||
externalWindow.webContents.on('did-finish-load', function() { |
|||
setTimeout(function() { |
|||
externalWindow.show(); |
|||
}, 40); |
|||
}); |
|||
} |
|||
|
|||
render() { |
|||
return ( |
|||
<div className="panel-body"> |
|||
<div className="col-sm-12 no-padding-left"> |
|||
<div className="support-box-wrapper"> |
|||
<div |
|||
className="support-box" |
|||
onClick={ () => this.openExternalWindow('http://support.supernet.org') }> |
|||
<img |
|||
src="assets/images/cryptologo/supernet.png" |
|||
alt="Support tickets" /> |
|||
<div className="support-box-title">{ translate('SETTINGS.SUPPORT_TICKETS') }</div> |
|||
<div className="support-box-link">support.supernet.org</div> |
|||
</div> |
|||
</div> |
|||
<div className="support-box-wrapper"> |
|||
<div |
|||
className="support-box" |
|||
onClick={ () => this.openExternalWindow('https://sprnt.slack.com') }> |
|||
<img |
|||
src="assets/images/support/slack-icon.png" |
|||
alt="Slack" /> |
|||
<div className="support-box-title">Slack</div> |
|||
<div className="support-box-link">sprnt.slack.com</div> |
|||
</div> |
|||
</div> |
|||
<div className="support-box-wrapper"> |
|||
<div |
|||
className="support-box" |
|||
onClick={ () => this.openExternalWindow('http://slackinvite.supernet.org') }> |
|||
<img |
|||
src="assets/images/support/slack-invite-icon.png" |
|||
alt="Slack invite" /> |
|||
<div className="support-box-title">{ translate('SETTINGS.GET_SLACK_INVITE') }</div> |
|||
<div className="support-box-link">slackinvite.supernet.org</div> |
|||
</div> |
|||
</div> |
|||
<div className="support-box-wrapper"> |
|||
<div |
|||
className="support-box" |
|||
onClick={ () => this.openExternalWindow('https://github.com/SuperNETorg/Agama') }> |
|||
<img |
|||
src="assets/images/support/github-icon.png" |
|||
alt="Github" /> |
|||
<div className="support-box-title">Github</div> |
|||
<div className="support-box-link">github.com/SuperNETorg/Agama</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
</div> |
|||
); |
|||
}; |
|||
} |
|||
|
|||
export default SupportPanel; |
Loading…
Reference in new issue