Error handling

This commit is contained in:
Scott E. Graves
2018-10-02 22:59:33 -05:00
parent 7e82690f5e
commit c55020fe0f
11 changed files with 158 additions and 64 deletions

View File

@@ -434,6 +434,10 @@ ipcMain.on(Constants.IPC_Set_Config_Values, (event, data) => {
setConfigValue(0); setConfigValue(0);
}); });
ipcMain.on(Constants.IPC_Shutdown, () => {
app.quit();
});
ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => { ipcMain.on(Constants.IPC_Unmount_Drive, (event, data) => {
helpers helpers
.stopProcessByPID(data.PID) .stopProcessByPID(data.PID)

View File

@@ -8,6 +8,7 @@ import CSSModules from 'react-css-modules';
import DependencyList from './components/DependencyList/DependencyList'; import DependencyList from './components/DependencyList/DependencyList';
import DownloadProgress from './components/DownloadProgress/DownloadProgress'; import DownloadProgress from './components/DownloadProgress/DownloadProgress';
import DropDown from './components/UI/DropDown/DropDown'; import DropDown from './components/UI/DropDown/DropDown';
import ErrorDetails from './components/ErrorDetails/ErrorDetails';
import Loading from './components/UI/Loading/Loading'; import Loading from './components/UI/Loading/Loading';
import Modal from './components/UI/Modal/Modal'; import Modal from './components/UI/Modal/Modal';
import MountItems from './containers/MountItems/MountItems'; import MountItems from './containers/MountItems/MountItems';
@@ -31,14 +32,13 @@ class App extends Component {
ipcRenderer.on(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete); ipcRenderer.on(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete);
ipcRenderer.on(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress); ipcRenderer.on(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress);
ipcRenderer.on(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete); ipcRenderer.on(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete);
ipcRenderer.on(Constants.IPC_Get_Platform_Reply, this.onGetPlatformReply);
ipcRenderer.on(Constants.IPC_Get_State_Reply, this.onGetStateReply); ipcRenderer.on(Constants.IPC_Get_State_Reply, this.onGetStateReply);
ipcRenderer.on(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply); ipcRenderer.on(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply);
ipcRenderer.on(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply); ipcRenderer.on(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply);
ipcRenderer.on(Constants.IPC_Install_Dependency_Reply, this.onInstallDependencyReply); ipcRenderer.on(Constants.IPC_Install_Dependency_Reply, this.onInstallDependencyReply);
ipcRenderer.on(Constants.IPC_Install_Upgrade_Reply, this.onInstallUpgradeReply); ipcRenderer.on(Constants.IPC_Install_Upgrade_Reply, this.onInstallUpgradeReply);
ipcRenderer.send(Constants.IPC_Get_Platform); ipcRenderer.send(Constants.IPC_Get_State, Constants.DATA_LOCATIONS[this.props.platform]);
Scheduler.scheduleJob('23 11 * * *', this.updateCheckScheduledJob); Scheduler.scheduleJob('23 11 * * *', this.updateCheckScheduledJob);
} }
} }
@@ -46,11 +46,12 @@ class App extends Component {
state = { state = {
AllowOptions: false, AllowOptions: false,
AllowDownload: false, AllowDownload: false,
AutoMountChecked: false, AutoMountProcessed: false,
ConfigStorageType: null, ConfigStorageType: null,
DisplayError: false, DisplayError: false,
Error: null, Error: null,
ErrorAction: null, ErrorAction: null,
ErrorCritical: false,
DownloadActive: false, DownloadActive: false,
DownloadProgress: 0.0, DownloadProgress: 0.0,
DownloadingDependency: false, DownloadingDependency: false,
@@ -109,6 +110,7 @@ class App extends Component {
AllowDownload: false, AllowDownload: false,
}); });
if (selectedVersion !== 'unavailable') {
if (ipcRenderer) { if (ipcRenderer) {
let dependencies = []; let dependencies = [];
if (this.state.LocationsLookup[selectedVersion] && this.state.LocationsLookup[selectedVersion].dependencies) { if (this.state.LocationsLookup[selectedVersion] && this.state.LocationsLookup[selectedVersion].dependencies) {
@@ -117,10 +119,28 @@ class App extends Component {
ipcRenderer.send(Constants.IPC_Check_Installed, { ipcRenderer.send(Constants.IPC_Check_Installed, {
Dependencies: dependencies, Dependencies: dependencies,
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
Version: selectedVersion, Version: selectedVersion,
}); });
} }
}
};
closeErrorDisplay = () => {
if (this.state.ErrorAction) {
this.state.ErrorAction();
}
if (this.state.ErrorCritical) {
if (ipcRenderer) {
ipcRenderer.send(Constants.IPC_Shutdown);
}
} else {
this.setState({
DisplayError: false,
Error: null,
});
}
}; };
componentWillUnmount = () => { componentWillUnmount = () => {
@@ -129,7 +149,6 @@ class App extends Component {
ipcRenderer.removeListener(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete); ipcRenderer.removeListener(Constants.IPC_Download_File_Complete, this.onDownloadFileComplete);
ipcRenderer.removeListener(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress); ipcRenderer.removeListener(Constants.IPC_Download_File_Progress, this.onDownloadFileProgress);
ipcRenderer.removeListener(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete); ipcRenderer.removeListener(Constants.IPC_Extract_Release_Complete, this.onExtractReleaseComplete);
ipcRenderer.removeListener(Constants.IPC_Get_Platform_Reply, this.onGetPlatformReply);
ipcRenderer.removeListener(Constants.IPC_Get_State_Reply, this.onGetStateReply); ipcRenderer.removeListener(Constants.IPC_Get_State_Reply, this.onGetStateReply);
ipcRenderer.removeListener(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply); ipcRenderer.removeListener(Constants.IPC_Grab_Releases_Reply, this.onGrabReleasesReply);
ipcRenderer.removeListener(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply); ipcRenderer.removeListener(Constants.IPC_Grab_UI_Releases_Reply, this.onGrabUiReleasesReply);
@@ -139,7 +158,7 @@ class App extends Component {
}; };
grabReleases = () => { grabReleases = () => {
if (this.state.Platform !== 'unknown') { if (this.props.platform !== 'unknown') {
if (ipcRenderer) { if (ipcRenderer) {
ipcRenderer.send(Constants.IPC_Grab_Releases); ipcRenderer.send(Constants.IPC_Grab_Releases);
ipcRenderer.send(Constants.IPC_Grab_UI_Releases); ipcRenderer.send(Constants.IPC_Grab_UI_Releases);
@@ -195,7 +214,7 @@ class App extends Component {
}); });
ipcRenderer.send(Constants.IPC_Download_File, { ipcRenderer.send(Constants.IPC_Download_File, {
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
Filename: fileName, Filename: fileName,
URL: url, URL: url,
}); });
@@ -242,7 +261,7 @@ class App extends Component {
}); });
ipcRenderer.send(Constants.IPC_Download_File, { ipcRenderer.send(Constants.IPC_Download_File, {
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
Filename: fileName, Filename: fileName,
URL: this.state.LocationsLookup[selectedVersion].urls[0], URL: this.state.LocationsLookup[selectedVersion].urls[0],
}); });
@@ -258,8 +277,8 @@ class App extends Component {
}); });
ipcRenderer.send(Constants.IPC_Download_File, { ipcRenderer.send(Constants.IPC_Download_File, {
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
Filename: this.state.Platform === 'win32' ? 'upgrade.exe' : 'upgrade', Filename: this.props.platform === 'win32' ? 'upgrade.exe' : 'upgrade',
URL: this.state.UpgradeData.urls[0], URL: this.state.UpgradeData.urls[0],
}); });
} else { } else {
@@ -277,7 +296,7 @@ class App extends Component {
}; };
notifyAutoMountProcessed = () => { notifyAutoMountProcessed = () => {
this.setState({AutoMountChecked: true}); this.setState({AutoMountProcessed: true});
}; };
notifyMountsBusy = (busy) => { notifyMountsBusy = (busy) => {
@@ -319,7 +338,7 @@ class App extends Component {
if (arg.data.Success) { if (arg.data.Success) {
const selectedVersion = this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]][this.state.Version]; const selectedVersion = this.state.VersionLookup[this.state.ReleaseTypes[this.state.Release]][this.state.Version];
ipcRenderer.send(Constants.IPC_Extract_Release, { ipcRenderer.send(Constants.IPC_Extract_Release, {
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
Source: arg.data.Destination, Source: arg.data.Destination,
Version: selectedVersion, Version: selectedVersion,
}); });
@@ -384,13 +403,6 @@ class App extends Component {
this.checkVersionInstalled(this.state.Release, this.state.Version); this.checkVersionInstalled(this.state.Release, this.state.Version);
}; };
onGetPlatformReply = (event, arg) => {
this.setState({
Platform: arg.data,
});
ipcRenderer.send(Constants.IPC_Get_State, Constants.DATA_LOCATIONS[arg.data]);
};
onGetStateReply = (event, arg) => { onGetStateReply = (event, arg) => {
if (arg.data) { if (arg.data) {
if (arg.data.Hyperspace.AutoMount === undefined) { if (arg.data.Hyperspace.AutoMount === undefined) {
@@ -431,13 +443,13 @@ class App extends Component {
axios.get(Constants.RELEASES_URL) axios.get(Constants.RELEASES_URL)
.then(response => { .then(response => {
const versionLookup = { const versionLookup = {
Alpha: response.data.Versions.Alpha[this.state.Platform], Alpha: response.data.Versions.Alpha[this.props.platform],
Beta: response.data.Versions.Beta[this.state.Platform], Beta: response.data.Versions.Beta[this.props.platform],
RC: response.data.Versions.RC[this.state.Platform], RC: response.data.Versions.RC[this.props.platform],
Release: response.data.Versions.Release[this.state.Platform], Release: response.data.Versions.Release[this.props.platform],
}; };
const locationsLookup = { const locationsLookup = {
...response.data.Locations[this.state.Platform], ...response.data.Locations[this.props.platform],
}; };
window.localStorage.setItem('releases', JSON.stringify({ window.localStorage.setItem('releases', JSON.stringify({
@@ -447,7 +459,6 @@ class App extends Component {
doUpdate(locationsLookup, versionLookup); doUpdate(locationsLookup, versionLookup);
}).catch(error => { }).catch(error => {
console.log(error);
const releases = window.localStorage.getItem('releases'); const releases = window.localStorage.getItem('releases');
if (releases && (releases.length > 0)) { if (releases && (releases.length > 0)) {
const obj = JSON.parse(releases); const obj = JSON.parse(releases);
@@ -456,7 +467,7 @@ class App extends Component {
doUpdate(locationsLookup, versionLookup); doUpdate(locationsLookup, versionLookup);
} else { } else {
// TODO Handle error this.setErrorState(error, null, true);
} }
}); });
}; };
@@ -466,17 +477,16 @@ class App extends Component {
.then(response => { .then(response => {
const data = response.data; const data = response.data;
if (data.Versions && if (data.Versions &&
data.Versions[this.state.Platform] && data.Versions[this.props.platform] &&
(data.Versions[this.state.Platform].length > 0) && (data.Versions[this.props.platform].length > 0) &&
(data.Versions[this.state.Platform][0] !== this.props.version)) { (data.Versions[this.props.platform][0] !== this.props.version)) {
this.setState({ this.setState({
UpgradeAvailable: true, UpgradeAvailable: true,
UpgradeDismissed: false, UpgradeDismissed: false,
UpgradeData: data.Locations[this.state.Platform][data.Versions[this.state.Platform][0]], UpgradeData: data.Locations[this.props.platform][data.Versions[this.props.platform][0]],
}); });
} }
}).catch(error => { }).catch(() => {
console.log(error);
this.setState({ this.setState({
UpgradeAvailable: false, UpgradeAvailable: false,
UpgradeData: {}, UpgradeData: {},
@@ -506,7 +516,7 @@ class App extends Component {
saveState = (release, version, sia, hyperspace)=> { saveState = (release, version, sia, hyperspace)=> {
if (ipcRenderer) { if (ipcRenderer) {
ipcRenderer.send(Constants.IPC_Save_State, { ipcRenderer.send(Constants.IPC_Save_State, {
Directory: Constants.DATA_LOCATIONS[this.state.Platform], Directory: Constants.DATA_LOCATIONS[this.props.platform],
State: { State: {
Hyperspace: hyperspace, Hyperspace: hyperspace,
Release: release, Release: release,
@@ -517,19 +527,18 @@ class App extends Component {
} }
}; };
setErrorState = (error, action) => { setErrorState = (error, action, critical) => {
this.setState({ this.setState({
DisplayError: true, DisplayError: true,
Error: error, Error: error,
ErrorAction: action, ErrorAction: action,
ErrorCritical: critical,
}); });
}; };
updateCheckScheduledJob = () => { updateCheckScheduledJob = () => {
if (this.state.Platform !== 'unknown') { if (this.props.platform !== 'unknown') {
if (ipcRenderer) { this.grabReleases();
ipcRenderer.send(Constants.IPC_Grab_UI_Releases);
}
} }
}; };
@@ -556,16 +565,22 @@ class App extends Component {
this.state.ConfigStorageType && this.state.ConfigStorageType &&
allowConfig; allowConfig;
const showUpgrade = !this.state.DisplayError && const showUpgrade = this.state.UpgradeAvailable &&
!this.state.DisplayError &&
!showConfig && !showConfig &&
!missingDependencies && !missingDependencies &&
!this.state.DownloadActive && !this.state.DownloadActive &&
this.state.UpgradeAvailable &&
!this.state.UpgradeDismissed; !this.state.UpgradeDismissed;
let errorDisplay = null; let errorDisplay = null;
if (this.state.DisplayError) { if (this.state.DisplayError) {
errorDisplay = (
<Modal critical>
<ErrorDetails closed={this.closeErrorDisplay}
critical={this.state.ErrorCritical}
error={this.state.Error}/>
</Modal>
);
} }
let configDisplay = null; let configDisplay = null;
@@ -573,7 +588,8 @@ class App extends Component {
configDisplay = ( configDisplay = (
<Modal> <Modal>
<Configuration closed={this.handleConfigClosed} <Configuration closed={this.handleConfigClosed}
directory={Constants.DATA_LOCATIONS[this.state.Platform]} directory={Constants.DATA_LOCATIONS[this.props.platform]}
errorHandler={this.setErrorState}
storageType={this.state.ConfigStorageType} storageType={this.state.ConfigStorageType}
version={selectedVersion} /> version={selectedVersion} />
</Modal> </Modal>
@@ -587,12 +603,12 @@ class App extends Component {
autoMountProcessed={this.notifyAutoMountProcessed} autoMountProcessed={this.notifyAutoMountProcessed}
changed={this.handleMountLocationChanged} changed={this.handleMountLocationChanged}
configClicked={this.handleConfigClicked} configClicked={this.handleConfigClicked}
directory={Constants.DATA_LOCATIONS[this.state.Platform]} directory={Constants.DATA_LOCATIONS[this.props.platform]}
disabled={!allowMount} errorHandler={this.setErrorState}
hyperspace={this.state.Hyperspace} hyperspace={this.state.Hyperspace}
mountsBusy={this.notifyMountsBusy} mountsBusy={this.notifyMountsBusy}
platform={this.state.Platform} platform={this.props.platform}
processAutoMount={!this.state.AutoMountChecked} processAutoMount={!this.state.AutoMountProcessed}
sia={this.state.Sia} sia={this.state.Sia}
version={this.state.RepertoryVersion}/>; version={this.state.RepertoryVersion}/>;
} }

View File

@@ -0,0 +1,11 @@
.Heading {
color: var(--text_color_error);
text-align: center;
margin-bottom: 4px;
}
.Content {
max-height: 60vh;
overflow-y: auto;
margin-bottom: 8px;
}

View File

@@ -0,0 +1,18 @@
import React from 'react';
import Box from '../UI/Box/Box';
import Button from '../UI/Button/Button';
import CSSModules from 'react-css-modules';
import styles from './ErrorDetails.css';
export default CSSModules((props) => {
return (
<Box dxStyle={{padding: '8px'}}>
<h1 styleName='Heading'>Application Error</h1>
<div styleName='Content'>
<p>{props.error.toString()}</p>
</div>
<Button clicked={props.closed}>Dismiss</Button>
</Box>
);
}, styles, {allowMultiple: true});

View File

@@ -17,3 +17,11 @@
transform: translate(-50%, -50%); transform: translate(-50%, -50%);
z-index: 2001; z-index: 2001;
} }
.Modal.Critical {
z-index: 2100;
}
.Content.Critical {
z-index: 2101;
}

View File

@@ -3,11 +3,20 @@ import CSSModules from 'react-css-modules';
import styles from './Modal.css' import styles from './Modal.css'
export default CSSModules((props) => { export default CSSModules((props) => {
let modalStyles = [];
let contentStyles = [];
modalStyles.push('Modal');
contentStyles.push('Content');
if (props.critical) {
modalStyles.push('Critical');
contentStyles.push('Critical');
}
return ( return (
<div <div
styleName='Modal' styleName={modalStyles.join(' ')}
onClick={props.clicked}> onClick={props.clicked}>
<div styleName='Content'> <div styleName={contentStyles.join(' ')}>
{props.children} {props.children}
</div> </div>
</div>); </div>);

View File

@@ -56,5 +56,7 @@ exports.IPC_Save_State = 'save_state';
exports.IPC_Set_Config_Values = 'set_config_values'; exports.IPC_Set_Config_Values = 'set_config_values';
exports.IPC_Set_Config_Values_Reply = 'set_config_values_reply'; exports.IPC_Set_Config_Values_Reply = 'set_config_values_reply';
exports.IPC_Shutdown = 'shutdown';
exports.IPC_Unmount_Drive = 'unmount_drive'; exports.IPC_Unmount_Drive = 'unmount_drive';
exports.IPC_Unmount_Drive_Reply = 'unmount_drive_reply'; exports.IPC_Unmount_Drive_Reply = 'unmount_drive_reply';

View File

@@ -155,6 +155,8 @@ class Configuration extends Component {
OriginalItemList: itemListCopy, OriginalItemList: itemListCopy,
OriginalObjectLookup: objectLookupCopy, OriginalObjectLookup: objectLookupCopy,
}); });
} else {
this.props.errorHandler(arg.data.Error);
} }
}; };
@@ -168,6 +170,10 @@ class Configuration extends Component {
StorageType: this.props.storageType, StorageType: this.props.storageType,
Version: this.props.version, Version: this.props.version,
}); });
} else {
this.props.errorHandler(arg.data.Error, () => {
this.props.closed();
});
} }
}; };
@@ -218,7 +224,7 @@ class Configuration extends Component {
<h1 style={{width: '100%', textAlign: 'center'}}>Save Changes?</h1> <h1 style={{width: '100%', textAlign: 'center'}}>Save Changes?</h1>
<table width='100%'><tbody> <table width='100%'><tbody>
<tr> <tr>
<td align='center' width='50%'><Button clicked={this.saveAndClose} disabled={this.state.Saving} >Yes</Button></td> <td align='center' width='50%'><Button clicked={this.saveAndClose} disabled={this.state.Saving}>Yes</Button></td>
<td align='center' width='50%'><Button clicked={this.props.closed} disabled={this.state.Saving}>No</Button></td> <td align='center' width='50%'><Button clicked={this.props.closed} disabled={this.state.Saving}>No</Button></td>
</tr> </tr>
</tbody></table> </tbody></table>
@@ -227,7 +233,7 @@ class Configuration extends Component {
); );
} }
let configurationItems = this.state.ItemList const configurationItems = this.state.ItemList
.map((k, i) => { .map((k, i) => {
return ( return (
((this.state.ShowAdvanced && k.advanced) || !k.advanced) ? ((this.state.ShowAdvanced && k.advanced) || !k.advanced) ?

View File

@@ -135,6 +135,8 @@ class MountItems extends Component {
} }
this.performAutoMount(); this.performAutoMount();
} else {
this.props.errorHandler(arg.data.Error);
} }
}; };

View File

@@ -9,6 +9,7 @@
--control_dark_transparent_background: rgba(15, 15, 15, 0.8); --control_dark_transparent_background: rgba(15, 15, 15, 0.8);
--text_color: rgba(200, 205, 220, 0.75); --text_color: rgba(200, 205, 220, 0.75);
--text_color_error: rgba(203, 120, 120, 0.75);
--text_color_hover: rgba(200, 205, 220, 0.75); --text_color_hover: rgba(200, 205, 220, 0.75);
--heading_text_color: rgba(140, 169, 203, 0.75); --heading_text_color: rgba(140, 169, 203, 0.75);
--heading_other_text_color: rgba(200, 205, 220, 0.75); --heading_other_text_color: rgba(200, 205, 220, 0.75);
@@ -17,7 +18,7 @@
* { * {
font-family: 'Nunito', sans-serif; font-family: 'Nunito', sans-serif;
font-size: 14px; font-size: 5vh;
} }
*::-moz-focus-inner { *::-moz-focus-inner {
@@ -61,3 +62,10 @@ h1 {
h2, h3 { h2, h3 {
color: var(--heading_other_text_color); color: var(--heading_other_text_color);
} }
p {
margin: 0;
padding: 0;
font-weight: normal;
color: var(--text_color);
}

View File

@@ -1,10 +1,20 @@
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import './index.css'; import './index.css';
import App from './App'; import App from './App';
import registerServiceWorker from './registerServiceWorker';
import packageJson from '../package.json'; import packageJson from '../package.json';
import registerServiceWorker from './registerServiceWorker';
const Constants = require('./constants');
if (!process.versions.hasOwnProperty('electron')) {
const ipcRenderer = ((window && window.require) ? window.require('electron').ipcRenderer : null);
if (ipcRenderer) {
ipcRenderer.on(Constants.IPC_Get_Platform_Reply, (event, arg) => {
ReactDOM.render(<App platform={arg.data} version={packageJson.version}/>, document.getElementById('root'));
registerServiceWorker();
});
ipcRenderer.send(Constants.IPC_Get_Platform);
}
}
ReactDOM.render(<App version={packageJson.version}/>, document.getElementById('root'));
registerServiceWorker();