diff --git a/react/change.log b/react/change.log index eef01f2..0fad6c0 100644 --- a/react/change.log +++ b/react/change.log @@ -19,6 +19,8 @@ front: - seed extra space(s) check - custom seed option - copy seed button +- native only mode +- app update back: - added cli route diff --git a/react/src/actions/actionCreators.js b/react/src/actions/actionCreators.js index c51d237..acbdd9e 100644 --- a/react/src/actions/actionCreators.js +++ b/react/src/actions/actionCreators.js @@ -66,6 +66,7 @@ export * from './actions/fullTxHistory'; export * from './actions/basiliskTxHistory'; export * from './actions/iguanaHelpers'; export * from './actions/cli'; +export * from './actions/update'; export let Config; diff --git a/react/src/actions/actions/update.js b/react/src/actions/actions/update.js new file mode 100644 index 0000000..457c22b --- /dev/null +++ b/react/src/actions/actions/update.js @@ -0,0 +1,54 @@ +import { + Config, + triggerToaster +} from '../actionCreators'; +import { + logGuiHttp, + guiLogState +} from './log'; + +export function checkForUpdateUIPromise() { + return new Promise((resolve, reject) => { + fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/update/patch/check`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'checkForUpdateUIPromise', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => resolve(json)) + }); +} + +export function updateUIPromise() { + return new Promise((resolve, reject) => { + fetch(`http://127.0.0.1:${Config.agamaPort}/shepherd/update/patch`, { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }) + .catch(function(error) { + console.log(error); + dispatch( + triggerToaster( + 'updateUIPromise', + 'Error', + 'error' + ) + ); + }) + .then(response => response.json()) + .then(json => resolve(json)) + }); +} \ No newline at end of file diff --git a/react/src/components/dashboard/settings/settings.js b/react/src/components/dashboard/settings/settings.js index 9e298ba..f1f370b 100644 --- a/react/src/components/dashboard/settings/settings.js +++ b/react/src/components/dashboard/settings/settings.js @@ -12,15 +12,26 @@ import { getAppConfig, saveAppConfig, getAppInfo, - shepherdCli + shepherdCli, + checkForUpdateUIPromise, + updateUIPromise } from '../../../actions/actionCreators'; import Store from '../../../store'; import { AppInfoTabRender, - SettingsRender + SettingsRender, + AppUpdateTabRender, } from './settings.render'; +import { SocketProvider } from 'socket.io-react'; +import io from 'socket.io-client'; + +const socket = io.connect('http://127.0.0.1:' + Config.agamaPort); +let updateProgressBar = { + patch: -1, +}; + /* TODO: 1) pre-select active coin in add node tab @@ -44,6 +55,10 @@ class Settings extends React.Component { exportWifKeysRaw: false, seedInputVisibility: false, nativeOnly: Config.iguanaLessMode, + updatePatch: null, + updateBins: null, + updateLog: [], + updateProgressPatch: null, }; this.exportWifKeys = this.exportWifKeys.bind(this); this.updateInput = this.updateInput.bind(this); @@ -57,6 +72,9 @@ class Settings extends React.Component { this._saveAppConfig = this._saveAppConfig.bind(this); this.exportWifKeysRaw = this.exportWifKeysRaw.bind(this); this.toggleSeedInputVisibility = this.toggleSeedInputVisibility.bind(this); + this._checkForUpdateUIPromise = this._checkForUpdateUIPromise.bind(this); + this._updateUIPromise = this._updateUIPromise.bind(this); + socket.on('patch', msg => this.updateSocketsData(msg)); } componentDidMount() { @@ -77,6 +95,115 @@ class Settings extends React.Component { } } + updateSocketsData(data) { + if (data && + data.msg && + data.msg.type === 'ui') { + + if (data.msg.status === 'progress' && + data.msg.progress && + data.msg.progress < 100) { + this.setState(Object.assign({}, this.state, { + updateProgressPatch: data.msg.progress, + })); + updateProgressBar.patch = data.msg.progress; + } else { + if (data.msg.status === 'progress' && + data.msg.progress && + data.msg.progress === 100) { + let _updateLog = []; + _updateLog.push('UI update downloaded. Verifying...'); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + })); + updateProgressBar.patch = 100; + } + + if (data.msg.status === 'done') { + let _updateLog = []; + _updateLog.push('UI is updated!'); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + updatePatch: null, + })); + updateProgressBar.patch = -1; + } + + if (data.msg.status === 'error') { + let _updateLog = []; + _updateLog.push('Error while verifying update file! Please retry again.'); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + })); + updateProgressBar.patch = -1; + } + } + } else { + if (data && + data.msg) { + let _updateLog = this.state.updateLog; + _updateLog.push(data.msg); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + })); + } + } + } + + _checkForUpdateUIPromise() { + let _updateLog = []; + _updateLog.push('Checking for UI update...'); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + })); + + checkForUpdateUIPromise() + .then((res) => { + let _updateLog = this.state.updateLog; + _updateLog.push(res.result === 'update' ? ('New UI update available ' + res.version.remote) : 'You have the lastest UI version'); + this.setState(Object.assign({}, this.state, { + updatePatch: res.result, + updateLog: _updateLog, + })); + }); + } + + _updateUIPromise() { + updateProgressBar.patch = 0; + let _updateLog = []; + _updateLog.push('Downloading UI update...'); + this.setState(Object.assign({}, this.state, { + updateLog: _updateLog, + })); + + updateUIPromise(); + } + + renderUpdateStatus() { + let items = []; + let patchProgressBar = null; + + for (let i = 0; i < this.state.updateLog.length; i++) { + items.push( +
{ this.state.updateLog[i] }
+ ); + } + + return ( +
+
+
Progress:
+
{ items }
+
-1 ? 'progress progress-sm' : 'hide' }> +
+
+
+
+ ); + } + toggleSeedInputVisibility() { this.setState({ seedInputVisibility: !this.state.seedInputVisibility, @@ -175,6 +302,10 @@ class Settings extends React.Component { return null; } + renderAppUpdateTab() { + return AppUpdateTabRender.call(this); + } + renderSNPeersList() { if (this.state.getPeersCoin) { const _getPeersCoin = this.state.getPeersCoin; diff --git a/react/src/components/dashboard/settings/settings.render.js b/react/src/components/dashboard/settings/settings.render.js index e58427c..765d385 100644 --- a/react/src/components/dashboard/settings/settings.render.js +++ b/react/src/components/dashboard/settings/settings.render.js @@ -4,6 +4,57 @@ import AddCoinOptionsCrypto from '../../addcoin/addcoinOptionsCrypto'; import AddCoinOptionsAC from '../../addcoin/addcoinOptionsAC'; import AddCoinOptionsACFiat from '../../addcoin/addcoinOptionsACFiat'; +export const AppUpdateTabRender = function() { + return ( +
this.openTab('AppUpdate', 10) }> +
+ + Update + +
+
+
+
+
UI update
+
+ + +
+
+
+
Binaries update
+
+ + +
+
+
+ { this.renderUpdateStatus() } +
+
+
+
+ ); +}; + export const AppInfoTabRender = function() { return (
+ + { this.renderAppUpdateTab() } diff --git a/react/webpack.config.js b/react/webpack.config.js index 2d761cf..bac8be8 100644 --- a/react/webpack.config.js +++ b/react/webpack.config.js @@ -29,7 +29,7 @@ const plugins = [ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks: Infinity, - filename: 'vendor-[hash].js', + filename: 'vendor.js', }), /* * The DefinePlugin allows you to create global constants which can be configured at compile time. @@ -84,7 +84,7 @@ const rules = [ { test: /\.(png|gif|jpg|svg)$/, include: imgPath, - use: 'url-loader?limit=20480&name=assets/[name]-[hash].[ext]', + use: 'url-loader?limit=20480&name=assets/[name].[ext]', }, ]; @@ -113,7 +113,7 @@ if (isProduction) { comments: false, }, }), - new ExtractTextPlugin('style-[hash].css') + new ExtractTextPlugin('style.css') ); // Production rules @@ -168,7 +168,7 @@ module.exports = { output: { path: buildPath, publicPath: '', - filename: 'app-[hash].js', + filename: 'app.js', }, module: { rules,