import React from 'react'; import './App.css'; import Box from './components/UI/Box/Box'; import Configuration from './containers/Configuration/Configuration'; import {connect} from 'react-redux'; import DependencyList from './components/DependencyList/DependencyList'; import DownloadProgress from './components/DownloadProgress/DownloadProgress'; import {extractFileNameFromURL} from './utils'; import ErrorDetails from './components/ErrorDetails/ErrorDetails'; import Grid from './components/UI/Grid/Grid'; import IPCContainer from './containers/IPCContainer/IPCContainer'; 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 ReleaseVersionDisplay from './components/ReleaseVersionDisplay/ReleaseVersionDisplay'; import {setProviderState} from './redux/actions/mount_actions'; import Text from './components/UI/Text/Text'; import UpgradeIcon from './components/UpgradeIcon/UpgradeIcon'; import UpgradeUI from './components/UpgradeUI/UpgradeUI'; import { downloadItem, setAllowDownload } from './redux/actions/download_actions'; import { checkInstalled, installDependency, installRelease, installUpgrade } from './redux/actions/install_actions'; import { detectUIUpgrade, loadReleases, setActiveRelease, setDismissUIUpgrade, setInstalledVersion, setReleaseUpgradeAvailable } from './redux/actions/release_version_actions'; const Constants = require('./constants'); const Scheduler = require('node-schedule'); class App extends IPCContainer { checkVersionInstalled = () => { this.props.setAllowDownload(false); const selectedVersion = this.getSelectedVersion(); if (selectedVersion !== 'unavailable') { let dependencies = []; if (this.props.LocationsLookup[selectedVersion] && this.props.LocationsLookup[selectedVersion].dependencies) { dependencies = this.props.LocationsLookup[selectedVersion].dependencies; } this.props.checkInstalled(dependencies, selectedVersion); } else { this.props.setInstalledVersion('none'); } }; _isMounted = false; componentDidMount() { this._isMounted = true; this.scheduledUpdateJob = Scheduler.scheduleJob('23 11 * * *', this.updateCheckScheduledJob); this.detectUpgrades(); } componentDidUpdate(prevProps) { if ((prevProps.Release !== this.props.Release) || (prevProps.ReleaseVersion !== this.props.ReleaseVersion) || (prevProps.VersionLookup !== this.props.VersionLookup)) { this.saveState(); this.checkVersionInstalled(); } else if (Object.keys(this.props.ProviderState).filter(k=> { return this.props.ProviderState[k] !== prevProps.ProviderState[k]; }).length > 0) { this.saveState(); } } componentWillUnmount() { this._isMounted = false; Scheduler.cancelJob(this.scheduledUpdateJob); super.componentWillUnmount(); } createModalConditionally = (condition, jsx, critical) => { const modalProps = {critical: critical}; return condition ? ({jsx}) : null; }; detectUpgrades = () => { if (this.props.AppPlatform !== 'unknown') { this.props.loadReleases(); this.props.detectUIUpgrade(); } }; getSelectedVersion = () => { return (this.props.ReleaseVersion === -1) ? 'unavailable' : this.props.VersionLookup[Constants.RELEASE_TYPES[this.props.Release]][this.props.ReleaseVersion]; }; handleDownloadDependency = url => { this.props.downloadItem(extractFileNameFromURL(url), Constants.INSTALL_TYPES.Dependency, url, this.onDownloadFileComplete); }; handleDownloadRelease = () => { const selectedVersion = this.getSelectedVersion(); const fileName = selectedVersion + '.zip'; this.props.downloadItem(fileName, Constants.INSTALL_TYPES.Release, this.props.LocationsLookup[selectedVersion].urls[0], this.onDownloadFileComplete); }; handleDownloadUpgrade = () => { const url = this.props.UpgradeData.urls[0]; const name = this.props.Platform === 'win32' ? 'upgrade.exe' : extractFileNameFromURL(url); this.props.downloadItem(name, Constants.INSTALL_TYPES.Upgrade, url, this.onDownloadFileComplete); }; installDependency = result => { if (result.Success) { this.props.installDependency(result.Destination, result.URL, this.onInstallDependencyComplete); } }; installRelease = result => { if (result.Success) { const selectedVersion = this.getSelectedVersion(); this.props.installRelease(result.Destination, selectedVersion, () => { if (this._isMounted) { this.checkVersionInstalled(); } }); } }; installUpgrade = result => { if (result.Success) { const info = this.props.LocationsLookup[this.props.AppPlatform][this.props.VersionLookup[this.props.AppPlatform][0]]; const sha256 = info.sha256; const signature = info.sig; this.props.installUpgrade(result.Destination, sha256, signature, !!result.SkipVerification, this.onInstallUpgradeComplete); } }; onDownloadFileComplete = (name, type, url, result) => { if (this._isMounted) { switch (type) { case Constants.INSTALL_TYPES.Dependency: this.installDependency(result); break; case Constants.INSTALL_TYPES.Release: this.installRelease(result); break; case Constants.INSTALL_TYPES.Upgrade: this.installUpgrade(result); break; default: this.props.notifyError('Unknown download type: ' + type); break; } } }; onInstallDependencyComplete = () => { if (this._isMounted) { this.checkVersionInstalled(); } }; onInstallUpgradeComplete = (source, result) => { if (this._isMounted && !result.Success) { this.props.notifyError(result.Error, false,() => { if (this._isMounted) { // TODO Prompt to verify if (result.AllowSkipVerification) { this.installUpgrade({ SkipVerification: true, Source: source, Success: true, }); } } }, false); } }; saveState = () => { if (this.props.AppReady) { let state = { Release: this.props.Release, Version: this.props.ReleaseVersion, }; for (const provider of Constants.PROVIDER_LIST) { state[provider] = this.props.ProviderState[provider]; } this.sendRequest(Constants.IPC_Save_State, { State: state }); } }; updateCheckScheduledJob = () => { if (this.props.AppPlatform !== 'unknown') { this.detectUpgrades(); } }; render() { const selectedVersion = this.getSelectedVersion(); const downloadEnabled = this.props.AllowDownload && !this.props.MountsBusy && !this.props.DownloadActive && (selectedVersion !== 'unavailable') && (selectedVersion !== this.props.InstalledVersion); const missingDependencies = (this.props.MissingDependencies.length > 0); const allowMount = this.props.InstalledVersion !== 'none' && !missingDependencies && !this.props.InstallActive; const allowConfig = this.props.LocationsLookup[selectedVersion] && this.props.LocationsLookup[selectedVersion].config_support; const allowSiaPrime = this.props.LocationsLookup[selectedVersion] && this.props.LocationsLookup[selectedVersion].siaprime_support; const noConsoleSupported = this.props.LocationsLookup[selectedVersion] && this.props.LocationsLookup[selectedVersion].no_console_supported; const showConfig = !missingDependencies && this.props.DisplayConfiguration && allowConfig; const showUpgrade = this.props.UpgradeAvailable && !this.props.DisplayError && !showConfig && !this.props.DownloadActive && !this.props.UpgradeDismissed; const showDependencies = !showUpgrade && missingDependencies && !this.props.DownloadActive; const configDisplay = this.createModalConditionally(showConfig, ); const dependencyDisplay = this.createModalConditionally(showDependencies, ); const downloadDisplay = this.createModalConditionally(this.props.DownloadActive, ); const errorDisplay = this.createModalConditionally(this.props.DisplayError, , true); const upgradeDisplay = this.createModalConditionally(showUpgrade, ); let mainContent = []; if (this.props.AppReady) { let key = 0; mainContent.push((
)); if (allowMount) { mainContent.push((
)); } } else { mainContent = } return (
{errorDisplay} {dependencyDisplay} {upgradeDisplay} {downloadDisplay} {configDisplay}
this.props.setDismissUIUpgrade(false)} col={dimensions => dimensions.columns - 6} colSpan={5} row={1} rowSpan={remain=>remain - 1}/>
{mainContent}
); } } const mapStateToProps = state => { return { AllowDownload: state.download.AllowDownload, AppPlatform: state.common.AppPlatform, AppReady: state.common.AppReady, DisplayConfiguration: state.mounts.DisplayConfiguration, DisplayError: state.error.DisplayError, DownloadActive: state.download.DownloadActive, DownloadType: state.download.DownloadType, InstallActive: state.install.InstallActive, InstallType: state.install.InstallType, InstalledVersion: state.relver.InstalledVersion, LocationsLookup: state.relver.LocationsLookup, MissingDependencies: state.install.MissingDependencies, MountsBusy: state.mounts.MountsBusy, Platform: state.common.Platform, ProviderState: state.mounts.ProviderState, Release: state.relver.Release, ReleaseVersion: state.relver.Version, UpgradeAvailable: state.relver.UpgradeAvailable, UpgradeData: state.relver.UpgradeData, UpgradeDismissed: state.relver.UpgradeDismissed, Version: state.common.Version, VersionLookup: state.relver.VersionLookup, }; }; const mapDispatchToProps = dispatch => { return { checkInstalled: (dependencies, version) => dispatch(checkInstalled(dependencies, version)), detectUIUpgrade: () => dispatch(detectUIUpgrade()), downloadItem: (name, type, url, completedCallback) => dispatch(downloadItem(name, type, url, completedCallback)), installDependency: (source, url, completedCallback) => dispatch(installDependency(source, url, completedCallback)), installRelease: (source, version, completedCallback) => dispatch(installRelease(source, version, completedCallback)), installUpgrade: (source, sha256, signature, skipVerification, completedCallback) => dispatch(installUpgrade(source, sha256, signature, skipVerification, completedCallback)), loadReleases: ()=> dispatch(loadReleases()), notifyError: (msg, critical, callback) => dispatch(notifyError(msg, critical, callback)), setActiveRelease: (release, version) => dispatch(setActiveRelease(release, version)), setAllowDownload: allow => dispatch(setAllowDownload(allow)), setDismissUIUpgrade: dismiss => dispatch(setDismissUIUpgrade(dismiss)), setInstalledVersion: version => dispatch(setInstalledVersion(version)), setProviderState: (provider, state) => dispatch(setProviderState(provider, state)), setReleaseUpgradeAvailable: available => dispatch(setReleaseUpgradeAvailable(available)), }; }; export default connect(mapStateToProps, mapDispatchToProps)(App);