From fa130c7dd18eea20cc412d9780f1c964b3492859 Mon Sep 17 00:00:00 2001 From: "Scott E. Graves" Date: Tue, 13 Aug 2019 14:06:50 -0500 Subject: [PATCH] [partial] #30: Add uninstall feature with reboot to handle WinFSP upgrades/downgrades --- public/electron.js | 7 ++++++ src/App.js | 11 +++++++-- .../DependencyList/DependencyList.js | 4 ++-- src/components/Reboot/Reboot.css | 11 +++++++++ src/components/Reboot/Reboot.js | 24 +++++++++++++++++++ src/constants.js | 2 ++ src/redux/actions/common_actions.js | 17 +++++++++++++ src/redux/actions/download_actions.js | 4 ++-- src/redux/actions/install_actions.js | 18 +++++++++----- src/redux/reducers/common_reducer.js | 14 +++++++++-- 10 files changed, 98 insertions(+), 14 deletions(-) create mode 100644 src/components/Reboot/Reboot.css create mode 100644 src/components/Reboot/Reboot.js diff --git a/public/electron.js b/public/electron.js index 69a5560..8eb484c 100644 --- a/public/electron.js +++ b/public/electron.js @@ -886,6 +886,13 @@ ipcMain.on(Constants.IPC_Mount_Drive, (event, data) => { } }); +ipcMain.on(Constants.IPC_Reboot_System, () => { + if (os.platform() === 'win32') { + helpers.executeAsync('shutdown.exe', ['/r', '/t', '30']); + } + closeApplication(); +}); + ipcMain.on(Constants.IPC_Save_State, (event, data) => { helpers.mkDirByPathSync(helpers.getDataDirectory()); const configFile = path.join(helpers.getDataDirectory(), 'settings.json'); diff --git a/src/App.js b/src/App.js index 713dbb5..1e48184 100644 --- a/src/App.js +++ b/src/App.js @@ -13,6 +13,7 @@ import Loading from './components/UI/Loading/Loading'; import Modal from './components/UI/Modal/Modal'; import MountItems from './containers/MountItems/MountItems'; import {notifyError} from './redux/actions/error_actions'; +import Reboot from './components/Reboot/Reboot'; import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay'; import {saveState} from './redux/actions/common_actions'; import Text from './components/UI/Text/Text'; @@ -93,6 +94,7 @@ class App extends IPCContainer { const showConfig = !missingDependencies && this.props.DisplayConfiguration && + !this.props.RebootRequired && allowConfig; const showUpgrade = this.props.UpgradeAvailable && @@ -100,12 +102,15 @@ class App extends IPCContainer { !showConfig && !this.props.DownloadActive && !this.props.UpgradeDismissed && - !this.props.InstallActive; + !this.props.InstallActive && + !this.props.RebootRequired; const showDependencies = !showUpgrade && missingDependencies && - !this.props.DownloadActive; + !this.props.DownloadActive && + !this.props.RebootRequired; + const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, ); const configDisplay = this.createModalConditionally(showConfig, ); const dependencyDisplay = this.createModalConditionally(showDependencies, ); const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, ); @@ -143,6 +148,7 @@ class App extends IPCContainer { {upgradeDisplay} {downloadDisplay} {configDisplay} + {rebootDisplay}
@@ -189,6 +195,7 @@ const mapStateToProps = state => { MissingDependencies: state.install.MissingDependencies, MountsBusy: state.mounts.MountsBusy, ProviderState: state.mounts.ProviderState, + RebootRequired: state.common.RebootRequired, Release: state.relver.Release, ReleaseVersion: state.relver.Version, UpgradeAvailable: state.relver.UpgradeAvailable, diff --git a/src/components/DependencyList/DependencyList.js b/src/components/DependencyList/DependencyList.js index 32db85f..d93e103 100644 --- a/src/components/DependencyList/DependencyList.js +++ b/src/components/DependencyList/DependencyList.js @@ -15,7 +15,7 @@ const mapStateToProps = state => { const mapDispatchToProps = (dispatch) => { return { - downloadItem: (name, type, url) => dispatch(downloadItem(name, type, url)) + downloadItem: (name, type, url, isWinFSP) => dispatch(downloadItem(name, type, url, isWinFSP)) }; }; @@ -24,7 +24,7 @@ export default connect(mapStateToProps, mapDispatchToProps)(props => { return ( props.downloadItem(extractFileNameFromURL(k.download), Constants.INSTALL_TYPES.Dependency, k.download)}/> + onDownload={()=>props.downloadItem(extractFileNameFromURL(k.download), Constants.INSTALL_TYPES.Dependency, k.download, k.is_winfsp)}/> ); }); diff --git a/src/components/Reboot/Reboot.css b/src/components/Reboot/Reboot.css new file mode 100644 index 0000000..26160e5 --- /dev/null +++ b/src/components/Reboot/Reboot.css @@ -0,0 +1,11 @@ +.RebootHeading { + color: var(--text_color_error); + text-align: center; + margin-bottom: 4px; +} + +.RebootContent { + max-height: 60vh; + overflow-y: auto; + margin-bottom: 8px; +} \ No newline at end of file diff --git a/src/components/Reboot/Reboot.js b/src/components/Reboot/Reboot.js new file mode 100644 index 0000000..242a3e9 --- /dev/null +++ b/src/components/Reboot/Reboot.js @@ -0,0 +1,24 @@ +import React from 'react'; +import './Reboot.css'; +import {connect} from 'react-redux'; +import Box from '../UI/Box/Box'; +import Button from '../UI/Button/Button'; +import {rebootSystem} from '../../redux/actions/common_actions'; + +const mapDispatchToProps = dispatch => { + return { + rebootSystem: () => dispatch(rebootSystem()), + }; +}; + +export default connect(null, mapDispatchToProps)(props => { + return ( + +

Reboot System

+
+

Repertory requires a system reboot to continue.

+
+ +
+ ); +}); \ No newline at end of file diff --git a/src/constants.js b/src/constants.js index f295fd1..28616ac 100644 --- a/src/constants.js +++ b/src/constants.js @@ -111,6 +111,8 @@ exports.IPC_Install_Upgrade_Reply = 'install_upgrade_reply'; exports.IPC_Mount_Drive = 'mount_drive'; exports.IPC_Mount_Drive_Reply = 'mount_drive_reply'; +exports.IPC_Reboot_System = 'reboot_system'; + exports.IPC_Save_State = 'save_state'; exports.IPC_Show_Window = 'show_window'; diff --git a/src/redux/actions/common_actions.js b/src/redux/actions/common_actions.js index de17bca..7dbe084 100644 --- a/src/redux/actions/common_actions.js +++ b/src/redux/actions/common_actions.js @@ -4,7 +4,24 @@ import {getIPCRenderer} from '../../utils'; const ipcRenderer = getIPCRenderer(); +export const notifyRebootRequired = createAction('common/notifyRebootRequired'); + +export const rebootSystem = () => { + return dispatch => { + dispatch(setApplicationReady(false)); + if (ipcRenderer) { + ipcRenderer.send(Constants.IPC_Reboot_System); + } + } +}; + export const setApplicationReady = createAction('common/setApplicationReady'); +export const setRebootRequired = () => { + return dispatch => { + dispatch(showWindow()); + dispatch(notifyRebootRequired(true)); + }; +}; export const showWindow = () => { return dispatch => { diff --git a/src/redux/actions/download_actions.js b/src/redux/actions/download_actions.js index 5c1d36d..2f8367e 100644 --- a/src/redux/actions/download_actions.js +++ b/src/redux/actions/download_actions.js @@ -25,7 +25,7 @@ export const setDownloadBegin = (name, type, url) => { export const setDownloadEnd = createAction('download/setDownloadEnd'); export const setDownloadProgress = createAction('download/setDownloadProgress'); -export const downloadItem = (name, type, urls) => { +export const downloadItem = (name, type, urls, isWinFSP) => { return (dispatch, getState) => { if (!Array.isArray(urls)) { urls = [urls]; @@ -35,7 +35,7 @@ export const downloadItem = (name, type, urls) => { if (result.Success) { switch (type) { case Constants.INSTALL_TYPES.Dependency: - dispatch(installDependency(result.Destination, result.URL)); + dispatch(installDependency(result.Destination, result.URL, isWinFSP)); break; case Constants.INSTALL_TYPES.Release: dispatch(installRelease(result.Destination)); diff --git a/src/redux/actions/install_actions.js b/src/redux/actions/install_actions.js index fb7612e..8c3fbd7 100644 --- a/src/redux/actions/install_actions.js +++ b/src/redux/actions/install_actions.js @@ -13,6 +13,7 @@ import { } from './release_version_actions'; import { setApplicationReady, + setRebootRequired, showWindow, shutdownApplication } from './common_actions'; @@ -81,7 +82,7 @@ export const checkVersionInstalled = () => { }; }; -export const installDependency = (source, url) => { +export const installDependency = (source, url, isWinFSP) => { return (dispatch, getState) => { if (ipcRenderer && !getState().install.InstallActive) { dispatch(setInstallActive(Constants.INSTALL_TYPES.Dependency)); @@ -89,11 +90,15 @@ export const installDependency = (source, url) => { const installDependencyComplete = (event, arg) => { const result = arg.data; const handleCompleted = ()=> { - ipcRenderer.send(Constants.IPC_Delete_File, { - FilePath: source, - }); - dispatch(setInstallComplete(result)); - dispatch(checkVersionInstalled()); + if (result.RebootRequired) { + dispatch(setRebootRequired()); + } else { + ipcRenderer.send(Constants.IPC_Delete_File, { + FilePath: source, + }); + dispatch(setInstallComplete(result)); + dispatch(checkVersionInstalled()); + } }; if (result.Success && source.toLowerCase().endsWith('.dmg')) { @@ -121,6 +126,7 @@ export const installDependency = (source, url) => { ipcRenderer.send(Constants.IPC_Install_Dependency, { Source: source, URL: url, + IsWinFSP: isWinFSP, }); } }; diff --git a/src/redux/reducers/common_reducer.js b/src/redux/reducers/common_reducer.js index 25ffde9..e0ef60e 100644 --- a/src/redux/reducers/common_reducer.js +++ b/src/redux/reducers/common_reducer.js @@ -1,11 +1,15 @@ import {createReducer} from 'redux-starter-kit'; -import {setApplicationReady} from '../actions/common_actions'; +import { + notifyRebootRequired, + setApplicationReady, +} from '../actions/common_actions'; export const createCommonReducer = (platform, appPlatform, version) => { return createReducer({ AppPlatform: appPlatform, AppReady: false, Platform: platform, + RebootRequired: false, Version: version, }, { [setApplicationReady]: (state, action) => { @@ -13,6 +17,12 @@ export const createCommonReducer = (platform, appPlatform, version) => { ...state, AppReady: action.payload, }; - } + }, + [notifyRebootRequired]: (state, action) => { + return { + ...state, + RebootRequired: action.payload, + }; + }, }); }; \ No newline at end of file