[partial] #30: Add uninstall feature with reboot to handle WinFSP upgrades/downgrades
This commit is contained in:
@@ -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) => {
|
ipcMain.on(Constants.IPC_Save_State, (event, data) => {
|
||||||
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
helpers.mkDirByPathSync(helpers.getDataDirectory());
|
||||||
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
const configFile = path.join(helpers.getDataDirectory(), 'settings.json');
|
||||||
|
|||||||
11
src/App.js
11
src/App.js
@@ -13,6 +13,7 @@ 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';
|
||||||
import {notifyError} from './redux/actions/error_actions';
|
import {notifyError} from './redux/actions/error_actions';
|
||||||
|
import Reboot from './components/Reboot/Reboot';
|
||||||
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
import ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay';
|
||||||
import {saveState} from './redux/actions/common_actions';
|
import {saveState} from './redux/actions/common_actions';
|
||||||
import Text from './components/UI/Text/Text';
|
import Text from './components/UI/Text/Text';
|
||||||
@@ -93,6 +94,7 @@ class App extends IPCContainer {
|
|||||||
|
|
||||||
const showConfig = !missingDependencies &&
|
const showConfig = !missingDependencies &&
|
||||||
this.props.DisplayConfiguration &&
|
this.props.DisplayConfiguration &&
|
||||||
|
!this.props.RebootRequired &&
|
||||||
allowConfig;
|
allowConfig;
|
||||||
|
|
||||||
const showUpgrade = this.props.UpgradeAvailable &&
|
const showUpgrade = this.props.UpgradeAvailable &&
|
||||||
@@ -100,12 +102,15 @@ class App extends IPCContainer {
|
|||||||
!showConfig &&
|
!showConfig &&
|
||||||
!this.props.DownloadActive &&
|
!this.props.DownloadActive &&
|
||||||
!this.props.UpgradeDismissed &&
|
!this.props.UpgradeDismissed &&
|
||||||
!this.props.InstallActive;
|
!this.props.InstallActive &&
|
||||||
|
!this.props.RebootRequired;
|
||||||
|
|
||||||
const showDependencies = !showUpgrade &&
|
const showDependencies = !showUpgrade &&
|
||||||
missingDependencies &&
|
missingDependencies &&
|
||||||
!this.props.DownloadActive;
|
!this.props.DownloadActive &&
|
||||||
|
!this.props.RebootRequired;
|
||||||
|
|
||||||
|
const rebootDisplay = this.createModalConditionally(this.props.RebootRequired, <Reboot />);
|
||||||
const configDisplay = this.createModalConditionally(showConfig, <Configuration version={selectedVersion} />);
|
const configDisplay = this.createModalConditionally(showConfig, <Configuration version={selectedVersion} />);
|
||||||
const dependencyDisplay = this.createModalConditionally(showDependencies, <DependencyList/>);
|
const dependencyDisplay = this.createModalConditionally(showDependencies, <DependencyList/>);
|
||||||
const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, <DownloadProgress/>);
|
||||||
@@ -143,6 +148,7 @@ class App extends IPCContainer {
|
|||||||
{upgradeDisplay}
|
{upgradeDisplay}
|
||||||
{downloadDisplay}
|
{downloadDisplay}
|
||||||
{configDisplay}
|
{configDisplay}
|
||||||
|
{rebootDisplay}
|
||||||
<div className={'AppContainer'}>
|
<div className={'AppContainer'}>
|
||||||
<div className={'AppHeader'}>
|
<div className={'AppHeader'}>
|
||||||
<Box>
|
<Box>
|
||||||
@@ -189,6 +195,7 @@ const mapStateToProps = state => {
|
|||||||
MissingDependencies: state.install.MissingDependencies,
|
MissingDependencies: state.install.MissingDependencies,
|
||||||
MountsBusy: state.mounts.MountsBusy,
|
MountsBusy: state.mounts.MountsBusy,
|
||||||
ProviderState: state.mounts.ProviderState,
|
ProviderState: state.mounts.ProviderState,
|
||||||
|
RebootRequired: state.common.RebootRequired,
|
||||||
Release: state.relver.Release,
|
Release: state.relver.Release,
|
||||||
ReleaseVersion: state.relver.Version,
|
ReleaseVersion: state.relver.Version,
|
||||||
UpgradeAvailable: state.relver.UpgradeAvailable,
|
UpgradeAvailable: state.relver.UpgradeAvailable,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ const mapStateToProps = state => {
|
|||||||
|
|
||||||
const mapDispatchToProps = (dispatch) => {
|
const mapDispatchToProps = (dispatch) => {
|
||||||
return {
|
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 (
|
return (
|
||||||
<Dependency key={i}
|
<Dependency key={i}
|
||||||
name={k.display}
|
name={k.display}
|
||||||
onDownload={()=>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)}/>
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
11
src/components/Reboot/Reboot.css
Normal file
11
src/components/Reboot/Reboot.css
Normal file
@@ -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;
|
||||||
|
}
|
||||||
24
src/components/Reboot/Reboot.js
Normal file
24
src/components/Reboot/Reboot.js
Normal file
@@ -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 (
|
||||||
|
<Box dxDark dxStyle={{padding: '8px'}}>
|
||||||
|
<h1 className={'RebootHeading'}>Reboot System</h1>
|
||||||
|
<div className={'RebootContent'}>
|
||||||
|
<p>Repertory requires a system reboot to continue.</p>
|
||||||
|
</div>
|
||||||
|
<Button clicked={()=>props.rebootSystem()}>Reboot Now</Button>
|
||||||
|
</Box>
|
||||||
|
);
|
||||||
|
});
|
||||||
@@ -111,6 +111,8 @@ exports.IPC_Install_Upgrade_Reply = 'install_upgrade_reply';
|
|||||||
exports.IPC_Mount_Drive = 'mount_drive';
|
exports.IPC_Mount_Drive = 'mount_drive';
|
||||||
exports.IPC_Mount_Drive_Reply = 'mount_drive_reply';
|
exports.IPC_Mount_Drive_Reply = 'mount_drive_reply';
|
||||||
|
|
||||||
|
exports.IPC_Reboot_System = 'reboot_system';
|
||||||
|
|
||||||
exports.IPC_Save_State = 'save_state';
|
exports.IPC_Save_State = 'save_state';
|
||||||
|
|
||||||
exports.IPC_Show_Window = 'show_window';
|
exports.IPC_Show_Window = 'show_window';
|
||||||
|
|||||||
@@ -4,7 +4,24 @@ import {getIPCRenderer} from '../../utils';
|
|||||||
|
|
||||||
const ipcRenderer = getIPCRenderer();
|
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 setApplicationReady = createAction('common/setApplicationReady');
|
||||||
|
export const setRebootRequired = () => {
|
||||||
|
return dispatch => {
|
||||||
|
dispatch(showWindow());
|
||||||
|
dispatch(notifyRebootRequired(true));
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
export const showWindow = () => {
|
export const showWindow = () => {
|
||||||
return dispatch => {
|
return dispatch => {
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ export const setDownloadBegin = (name, type, url) => {
|
|||||||
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
export const setDownloadEnd = createAction('download/setDownloadEnd');
|
||||||
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
export const setDownloadProgress = createAction('download/setDownloadProgress');
|
||||||
|
|
||||||
export const downloadItem = (name, type, urls) => {
|
export const downloadItem = (name, type, urls, isWinFSP) => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
if (!Array.isArray(urls)) {
|
if (!Array.isArray(urls)) {
|
||||||
urls = [urls];
|
urls = [urls];
|
||||||
@@ -35,7 +35,7 @@ export const downloadItem = (name, type, urls) => {
|
|||||||
if (result.Success) {
|
if (result.Success) {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case Constants.INSTALL_TYPES.Dependency:
|
case Constants.INSTALL_TYPES.Dependency:
|
||||||
dispatch(installDependency(result.Destination, result.URL));
|
dispatch(installDependency(result.Destination, result.URL, isWinFSP));
|
||||||
break;
|
break;
|
||||||
case Constants.INSTALL_TYPES.Release:
|
case Constants.INSTALL_TYPES.Release:
|
||||||
dispatch(installRelease(result.Destination));
|
dispatch(installRelease(result.Destination));
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import {
|
|||||||
} from './release_version_actions';
|
} from './release_version_actions';
|
||||||
import {
|
import {
|
||||||
setApplicationReady,
|
setApplicationReady,
|
||||||
|
setRebootRequired,
|
||||||
showWindow,
|
showWindow,
|
||||||
shutdownApplication
|
shutdownApplication
|
||||||
} from './common_actions';
|
} from './common_actions';
|
||||||
@@ -81,7 +82,7 @@ export const checkVersionInstalled = () => {
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
export const installDependency = (source, url) => {
|
export const installDependency = (source, url, isWinFSP) => {
|
||||||
return (dispatch, getState) => {
|
return (dispatch, getState) => {
|
||||||
if (ipcRenderer && !getState().install.InstallActive) {
|
if (ipcRenderer && !getState().install.InstallActive) {
|
||||||
dispatch(setInstallActive(Constants.INSTALL_TYPES.Dependency));
|
dispatch(setInstallActive(Constants.INSTALL_TYPES.Dependency));
|
||||||
@@ -89,11 +90,15 @@ export const installDependency = (source, url) => {
|
|||||||
const installDependencyComplete = (event, arg) => {
|
const installDependencyComplete = (event, arg) => {
|
||||||
const result = arg.data;
|
const result = arg.data;
|
||||||
const handleCompleted = ()=> {
|
const handleCompleted = ()=> {
|
||||||
|
if (result.RebootRequired) {
|
||||||
|
dispatch(setRebootRequired());
|
||||||
|
} else {
|
||||||
ipcRenderer.send(Constants.IPC_Delete_File, {
|
ipcRenderer.send(Constants.IPC_Delete_File, {
|
||||||
FilePath: source,
|
FilePath: source,
|
||||||
});
|
});
|
||||||
dispatch(setInstallComplete(result));
|
dispatch(setInstallComplete(result));
|
||||||
dispatch(checkVersionInstalled());
|
dispatch(checkVersionInstalled());
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if (result.Success && source.toLowerCase().endsWith('.dmg')) {
|
if (result.Success && source.toLowerCase().endsWith('.dmg')) {
|
||||||
@@ -121,6 +126,7 @@ export const installDependency = (source, url) => {
|
|||||||
ipcRenderer.send(Constants.IPC_Install_Dependency, {
|
ipcRenderer.send(Constants.IPC_Install_Dependency, {
|
||||||
Source: source,
|
Source: source,
|
||||||
URL: url,
|
URL: url,
|
||||||
|
IsWinFSP: isWinFSP,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
import {createReducer} from 'redux-starter-kit';
|
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) => {
|
export const createCommonReducer = (platform, appPlatform, version) => {
|
||||||
return createReducer({
|
return createReducer({
|
||||||
AppPlatform: appPlatform,
|
AppPlatform: appPlatform,
|
||||||
AppReady: false,
|
AppReady: false,
|
||||||
Platform: platform,
|
Platform: platform,
|
||||||
|
RebootRequired: false,
|
||||||
Version: version,
|
Version: version,
|
||||||
}, {
|
}, {
|
||||||
[setApplicationReady]: (state, action) => {
|
[setApplicationReady]: (state, action) => {
|
||||||
@@ -13,6 +17,12 @@ export const createCommonReducer = (platform, appPlatform, version) => {
|
|||||||
...state,
|
...state,
|
||||||
AppReady: action.payload,
|
AppReady: action.payload,
|
||||||
};
|
};
|
||||||
}
|
},
|
||||||
|
[notifyRebootRequired]: (state, action) => {
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
RebootRequired: action.payload,
|
||||||
|
};
|
||||||
|
},
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user