parent
dbdb8e4436
commit
aafa9cb6be
|
@ -99,6 +99,7 @@ class GeneralSettings extends Component {
|
||||||
isMono,
|
isMono,
|
||||||
isWindows,
|
isWindows,
|
||||||
mode,
|
mode,
|
||||||
|
packageUpdateMechanism,
|
||||||
onInputChange,
|
onInputChange,
|
||||||
onConfirmResetApiKey,
|
onConfirmResetApiKey,
|
||||||
...otherProps
|
...otherProps
|
||||||
|
@ -161,6 +162,7 @@ class GeneralSettings extends Component {
|
||||||
advancedSettings={advancedSettings}
|
advancedSettings={advancedSettings}
|
||||||
settings={settings}
|
settings={settings}
|
||||||
isMono={isMono}
|
isMono={isMono}
|
||||||
|
packageUpdateMechanism={packageUpdateMechanism}
|
||||||
onInputChange={onInputChange}
|
onInputChange={onInputChange}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
@ -202,6 +204,7 @@ GeneralSettings.propTypes = {
|
||||||
isMono: PropTypes.bool.isRequired,
|
isMono: PropTypes.bool.isRequired,
|
||||||
isWindows: PropTypes.bool.isRequired,
|
isWindows: PropTypes.bool.isRequired,
|
||||||
mode: PropTypes.string.isRequired,
|
mode: PropTypes.string.isRequired,
|
||||||
|
packageUpdateMechanism: PropTypes.string.isRequired,
|
||||||
onInputChange: PropTypes.func.isRequired,
|
onInputChange: PropTypes.func.isRequired,
|
||||||
onConfirmResetApiKey: PropTypes.func.isRequired,
|
onConfirmResetApiKey: PropTypes.func.isRequired,
|
||||||
onConfirmRestart: PropTypes.func.isRequired
|
onConfirmRestart: PropTypes.func.isRequired
|
||||||
|
|
|
@ -27,6 +27,7 @@ function createMapStateToProps() {
|
||||||
isMono: systemStatus.isMono,
|
isMono: systemStatus.isMono,
|
||||||
isWindows: systemStatus.isWindows,
|
isWindows: systemStatus.isWindows,
|
||||||
mode: systemStatus.mode,
|
mode: systemStatus.mode,
|
||||||
|
packageUpdateMechanism: systemStatus.packageUpdateMechanism,
|
||||||
...sectionSettings
|
...sectionSettings
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import titleCase from 'Utilities/String/titleCase';
|
||||||
import { inputTypes, sizes } from 'Helpers/Props';
|
import { inputTypes, sizes } from 'Helpers/Props';
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
|
@ -11,6 +12,7 @@ function UpdateSettings(props) {
|
||||||
advancedSettings,
|
advancedSettings,
|
||||||
settings,
|
settings,
|
||||||
isMono,
|
isMono,
|
||||||
|
packageUpdateMechanism,
|
||||||
onInputChange
|
onInputChange
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
@ -30,6 +32,13 @@ function UpdateSettings(props) {
|
||||||
{ key: 'script', value: 'Script' }
|
{ key: 'script', value: 'Script' }
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if (packageUpdateMechanism !== 'builtIn') {
|
||||||
|
updateOptions.push({
|
||||||
|
key: packageUpdateMechanism,
|
||||||
|
value: titleCase(packageUpdateMechanism)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<FieldSet legend="Updates">
|
<FieldSet legend="Updates">
|
||||||
<FormGroup
|
<FormGroup
|
||||||
|
@ -50,58 +59,58 @@ function UpdateSettings(props) {
|
||||||
|
|
||||||
{
|
{
|
||||||
isMono &&
|
isMono &&
|
||||||
<div>
|
<div>
|
||||||
<FormGroup
|
<FormGroup
|
||||||
advancedSettings={advancedSettings}
|
advancedSettings={advancedSettings}
|
||||||
isAdvanced={true}
|
isAdvanced={true}
|
||||||
size={sizes.MEDIUM}
|
size={sizes.MEDIUM}
|
||||||
>
|
>
|
||||||
<FormLabel>Automatic</FormLabel>
|
<FormLabel>Automatic</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="updateAutomatically"
|
name="updateAutomatically"
|
||||||
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
|
helpText="Automatically download and install updates. You will still be able to install from System: Updates"
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...updateAutomatically}
|
{...updateAutomatically}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
<FormGroup
|
|
||||||
advancedSettings={advancedSettings}
|
|
||||||
isAdvanced={true}
|
|
||||||
>
|
|
||||||
<FormLabel>Mechanism</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.SELECT}
|
|
||||||
name="updateMechanism"
|
|
||||||
values={updateOptions}
|
|
||||||
helpText="Use Sonarr's built-in updater or a script"
|
|
||||||
helpLink="https://github.com/Sonarr/Sonarr/wiki/Updating"
|
|
||||||
onChange={onInputChange}
|
|
||||||
{...updateMechanism}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
|
|
||||||
{
|
|
||||||
updateMechanism.value === 'script' &&
|
|
||||||
<FormGroup
|
<FormGroup
|
||||||
advancedSettings={advancedSettings}
|
advancedSettings={advancedSettings}
|
||||||
isAdvanced={true}
|
isAdvanced={true}
|
||||||
>
|
>
|
||||||
<FormLabel>Script Path</FormLabel>
|
<FormLabel>Mechanism</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.TEXT}
|
type={inputTypes.SELECT}
|
||||||
name="updateScriptPath"
|
name="updateMechanism"
|
||||||
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
|
values={updateOptions}
|
||||||
|
helpText="Use Sonarr's built-in updater or a script"
|
||||||
|
helpLink="https://github.com/Sonarr/Sonarr/wiki/Updating"
|
||||||
onChange={onInputChange}
|
onChange={onInputChange}
|
||||||
{...updateScriptPath}
|
{...updateMechanism}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
}
|
|
||||||
</div>
|
{
|
||||||
|
updateMechanism.value === 'script' &&
|
||||||
|
<FormGroup
|
||||||
|
advancedSettings={advancedSettings}
|
||||||
|
isAdvanced={true}
|
||||||
|
>
|
||||||
|
<FormLabel>Script Path</FormLabel>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.TEXT}
|
||||||
|
name="updateScriptPath"
|
||||||
|
helpText="Path to a custom script that takes an extracted update package and handle the remainder of the update process"
|
||||||
|
onChange={onInputChange}
|
||||||
|
{...updateScriptPath}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
</FieldSet>
|
</FieldSet>
|
||||||
);
|
);
|
||||||
|
@ -111,6 +120,7 @@ UpdateSettings.propTypes = {
|
||||||
advancedSettings: PropTypes.bool.isRequired,
|
advancedSettings: PropTypes.bool.isRequired,
|
||||||
settings: PropTypes.object.isRequired,
|
settings: PropTypes.object.isRequired,
|
||||||
isMono: PropTypes.bool.isRequired,
|
isMono: PropTypes.bool.isRequired,
|
||||||
|
packageUpdateMechanism: PropTypes.string.isRequired,
|
||||||
onInputChange: PropTypes.func.isRequired
|
onInputChange: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,8 +1,4 @@
|
||||||
.updateAvailable {
|
.messageContainer {
|
||||||
display: flex;
|
|
||||||
}
|
|
||||||
|
|
||||||
.upToDate {
|
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
|
@ -12,7 +8,7 @@
|
||||||
font-size: 30px;
|
font-size: 30px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.upToDateMessage {
|
.message {
|
||||||
padding-left: 5px;
|
padding-left: 5px;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: 30px;
|
line-height: 30px;
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component, Fragment } from 'react';
|
||||||
import { icons, kinds } from 'Helpers/Props';
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
import formatDate from 'Utilities/Date/formatDate';
|
import formatDate from 'Utilities/Date/formatDate';
|
||||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||||
|
@ -21,15 +21,18 @@ class Updates extends Component {
|
||||||
const {
|
const {
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
updatesError,
|
||||||
|
generalSettingsError,
|
||||||
items,
|
items,
|
||||||
isInstallingUpdate,
|
isInstallingUpdate,
|
||||||
|
updateMechanism,
|
||||||
shortDateFormat,
|
shortDateFormat,
|
||||||
onInstallLatestPress
|
onInstallLatestPress
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const hasUpdates = isPopulated && !error && items.length > 0;
|
const hasError = !!(updatesError || generalSettingsError);
|
||||||
const noUpdates = isPopulated && !error && !items.length;
|
const hasUpdates = isPopulated && !hasError && items.length > 0;
|
||||||
|
const noUpdates = isPopulated && !hasError && !items.length;
|
||||||
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
|
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
|
||||||
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
|
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ class Updates extends Component {
|
||||||
<PageContent title="Updates">
|
<PageContent title="Updates">
|
||||||
<PageContentBodyConnector>
|
<PageContentBodyConnector>
|
||||||
{
|
{
|
||||||
!isPopulated && !error &&
|
!isPopulated && !hasError &&
|
||||||
<LoadingIndicator />
|
<LoadingIndicator />
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,15 +51,30 @@ class Updates extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
hasUpdateToInstall &&
|
hasUpdateToInstall &&
|
||||||
<div className={styles.updateAvailable}>
|
<div className={styles.messageContainer}>
|
||||||
<SpinnerButton
|
{
|
||||||
className={styles.updateAvailable}
|
updateMechanism === 'builtIn' || updateMechanism === 'script' ?
|
||||||
kind={kinds.PRIMARY}
|
<SpinnerButton
|
||||||
isSpinning={isInstallingUpdate}
|
className={styles.updateAvailable}
|
||||||
onPress={onInstallLatestPress}
|
kind={kinds.PRIMARY}
|
||||||
>
|
isSpinning={isInstallingUpdate}
|
||||||
Install Latest
|
onPress={onInstallLatestPress}
|
||||||
</SpinnerButton>
|
>
|
||||||
|
Install Latest
|
||||||
|
</SpinnerButton> :
|
||||||
|
|
||||||
|
<Fragment>
|
||||||
|
<Icon
|
||||||
|
name={icons.WARNING}
|
||||||
|
kind={kinds.WARNING}
|
||||||
|
size={30}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.message}>
|
||||||
|
Unable to update Sonarr. Sonarr is configured to use an external update mechanism
|
||||||
|
</div>
|
||||||
|
</Fragment>
|
||||||
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isFetching &&
|
isFetching &&
|
||||||
|
@ -70,13 +88,14 @@ class Updates extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
noUpdateToInstall &&
|
noUpdateToInstall &&
|
||||||
<div className={styles.upToDate}>
|
<div className={styles.messageContainer}>
|
||||||
<Icon
|
<Icon
|
||||||
className={styles.upToDateIcon}
|
className={styles.upToDateIcon}
|
||||||
name={icons.CHECK_CIRCLE}
|
name={icons.CHECK_CIRCLE}
|
||||||
size={30}
|
size={30}
|
||||||
/>
|
/>
|
||||||
<div className={styles.upToDateMessage}>
|
|
||||||
|
<div className={styles.message}>
|
||||||
The latest version of Sonarr is already installed
|
The latest version of Sonarr is already installed
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -144,11 +163,18 @@ class Updates extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!!error &&
|
!!updatesError &&
|
||||||
<div>
|
<div>
|
||||||
Failed to fetch updates
|
Failed to fetch updates
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
!!generalSettingsError &&
|
||||||
|
<div>
|
||||||
|
Failed to update settings
|
||||||
|
</div>
|
||||||
|
}
|
||||||
</PageContentBodyConnector>
|
</PageContentBodyConnector>
|
||||||
</PageContent>
|
</PageContent>
|
||||||
);
|
);
|
||||||
|
@ -159,9 +185,11 @@ class Updates extends Component {
|
||||||
Updates.propTypes = {
|
Updates.propTypes = {
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
updatesError: PropTypes.object,
|
||||||
|
generalSettingsError: PropTypes.object,
|
||||||
items: PropTypes.array.isRequired,
|
items: PropTypes.array.isRequired,
|
||||||
isInstallingUpdate: PropTypes.bool.isRequired,
|
isInstallingUpdate: PropTypes.bool.isRequired,
|
||||||
|
updateMechanism: PropTypes.string.isRequired,
|
||||||
shortDateFormat: PropTypes.string.isRequired,
|
shortDateFormat: PropTypes.string.isRequired,
|
||||||
onInstallLatestPress: PropTypes.func.isRequired
|
onInstallLatestPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
|
import { fetchGeneralSettings } from 'Store/Actions/settingsActions';
|
||||||
import { fetchUpdates } from 'Store/Actions/systemActions';
|
import { fetchUpdates } from 'Store/Actions/systemActions';
|
||||||
import { executeCommand } from 'Store/Actions/commandActions';
|
import { executeCommand } from 'Store/Actions/commandActions';
|
||||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||||
|
@ -12,22 +13,26 @@ import Updates from './Updates';
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.system.updates,
|
(state) => state.system.updates,
|
||||||
|
(state) => state.settings.general,
|
||||||
createUISettingsSelector(),
|
createUISettingsSelector(),
|
||||||
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
|
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
|
||||||
(updates, uiSettings, isInstallingUpdate) => {
|
(updates, generalSettings, uiSettings, isInstallingUpdate) => {
|
||||||
const {
|
const {
|
||||||
isFetching,
|
error: updatesError,
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items
|
items
|
||||||
} = updates;
|
} = updates;
|
||||||
|
|
||||||
|
const isFetching = updates.isFetching || generalSettings.isFetching;
|
||||||
|
const isPopulated = updates.isPopulated && generalSettings.isPopulated;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
updatesError,
|
||||||
|
generalSettingsError: generalSettings.error,
|
||||||
items,
|
items,
|
||||||
isInstallingUpdate,
|
isInstallingUpdate,
|
||||||
|
updateMechanism: generalSettings.item.updateMechanism,
|
||||||
shortDateFormat: uiSettings.shortDateFormat
|
shortDateFormat: uiSettings.shortDateFormat
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -35,8 +40,9 @@ function createMapStateToProps() {
|
||||||
}
|
}
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
const mapDispatchToProps = {
|
||||||
fetchUpdates,
|
dispatchFetchUpdates: fetchUpdates,
|
||||||
executeCommand
|
dispatchFetchGeneralSettings: fetchGeneralSettings,
|
||||||
|
dispatchExecuteCommand: executeCommand
|
||||||
};
|
};
|
||||||
|
|
||||||
class UpdatesConnector extends Component {
|
class UpdatesConnector extends Component {
|
||||||
|
@ -45,14 +51,15 @@ class UpdatesConnector extends Component {
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchUpdates();
|
this.props.dispatchFetchUpdates();
|
||||||
|
this.props.dispatchFetchGeneralSettings();
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onInstallLatestPress = () => {
|
onInstallLatestPress = () => {
|
||||||
this.props.executeCommand({ name: commandNames.APPLICATION_UPDATE });
|
this.props.dispatchExecuteCommand({ name: commandNames.APPLICATION_UPDATE });
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -69,8 +76,9 @@ class UpdatesConnector extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdatesConnector.propTypes = {
|
UpdatesConnector.propTypes = {
|
||||||
fetchUpdates: PropTypes.func.isRequired,
|
dispatchFetchUpdates: PropTypes.func.isRequired,
|
||||||
executeCommand: PropTypes.func.isRequired
|
dispatchFetchGeneralSettings: PropTypes.func.isRequired,
|
||||||
|
dispatchExecuteCommand: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(UpdatesConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(UpdatesConnector);
|
||||||
|
|
Loading…
Reference in New Issue