Initial Commit Rework

This commit is contained in:
Qstick 2017-09-03 22:20:56 -04:00
parent 74a4cc048c
commit 95051cbd63
2483 changed files with 101351 additions and 111396 deletions

View file

@ -0,0 +1,4 @@
.title {
margin-top: 10px;
font-size: 16px;
}

View file

@ -0,0 +1,45 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import styles from './UpdateChanges.css';
class UpdateChanges extends Component {
//
// Render
render() {
const {
title,
changes
} = this.props;
if (changes.length === 0) {
return null;
}
return (
<div>
<div className={styles.title}>{title}</div>
<ul>
{
changes.map((change, index) => {
return (
<li key={index}>
{change}
</li>
)
})
}
</ul>
</div>
);
}
}
UpdateChanges.propTypes = {
title: PropTypes.string.isRequired,
changes: PropTypes.arrayOf(PropTypes.string)
};
export default UpdateChanges

View file

@ -0,0 +1,46 @@
.upToDate {
display: flex;
margin-bottom: 20px;
}
.upToDateIcon {
color: #37bc9b;
font-size: 30px;
}
.upToDateMessage {
padding-left: 5px;
font-size: 18px;
line-height: 30px;
}
.update {
margin-top: 20px;
}
.info {
display: flex;
margin-bottom: 10px;
padding-bottom: 5px;
border-bottom: 1px solid #e5e5e5;
line-height: 21px;
}
.version {
font-size: 21px;
}
.space {
padding: 0 5px;
}
.date {
font-size: 16px;
}
.branch {
composes: label from 'Components/Label.css';
margin-left: 10px;
font-size: 14px;
}

View file

@ -0,0 +1,149 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds } from 'Helpers/Props';
import formatDate from 'Utilities/Date/formatDate';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import SpinnerButton from 'Components/Link/SpinnerButton';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import PageContent from 'Components/Page/PageContent';
import PageContentBodyConnector from 'Components/Page/PageContentBodyConnector';
import UpdateChanges from './UpdateChanges';
import styles from './Updates.css';
class Updates extends Component {
//
// Render
render() {
const {
isPopulated,
error,
items,
isInstallingUpdate,
shortDateFormat,
onInstallLatestPress
} = this.props;
const hasUpdates = isPopulated && !error && items.length > 0;
const noUpdates = isPopulated && !error && !items.length;
const hasUpdateToInstall = hasUpdates && _.some(items, { installable: true, latest: true });
const noUpdateToInstall = hasUpdates && !hasUpdateToInstall;
return (
<PageContent title="Updates">
<PageContentBodyConnector>
{
!isPopulated &&
<LoadingIndicator />
}
{
noUpdates &&
<div>No updates are available</div>
}
{
hasUpdateToInstall &&
<SpinnerButton
kind={kinds.PRIMARY}
className={styles.updateAvailable}
isSpinning={isInstallingUpdate}
onPress={onInstallLatestPress}
>
Install Latest
</SpinnerButton>
}
{
noUpdateToInstall &&
<div className={styles.upToDate}>
<Icon
className={styles.upToDateIcon}
name="fa fa-check-circle"
size={30}
/>
<div className={styles.upToDateMessage}>
The latest version of Sonarr is already installed
</div>
</div>
}
{
hasUpdates &&
<div>
{
items.map((update) => {
const hasChanges = !!update.changes;
return (
<div
key={update.version}
className={styles.update}
>
<div className={styles.info}>
<div className={styles.version}>{update.version}</div>
<div className={styles.space}>&mdash;</div>
<div className={styles.date}>{formatDate(update.releaseDate, shortDateFormat)}</div>
{
update.branch !== 'master' &&
<Label
className={styles.branch}
>
{update.branch}
</Label>
}
</div>
{
!hasChanges &&
<div>Maintenance release</div>
}
{
hasChanges &&
<div className={styles.changes}>
<UpdateChanges
title="New"
changes={update.changes.new}
/>
<UpdateChanges
title="Fixed"
changes={update.changes.fixed}
/>
</div>
}
</div>
);
})
}
</div>
}
{
!!error &&
<div className={styles.upToDateMessage}>
Failed to fetch updates
</div>
}
</PageContentBodyConnector>
</PageContent>
);
}
}
Updates.propTypes = {
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object.isRequired,
items: PropTypes.array.isRequired,
isInstallingUpdate: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired,
onInstallLatestPress: PropTypes.func.isRequired
};
export default Updates;

View file

@ -0,0 +1,74 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchUpdates } from 'Store/Actions/systemActions';
import { executeCommand } from 'Store/Actions/commandActions';
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import * as commandNames from 'Commands/commandNames';
import Updates from './Updates';
function createMapStateToProps() {
return createSelector(
(state) => state.system.updates,
createUISettingsSelector(),
createCommandExecutingSelector(commandNames.APPLICATION_UPDATE),
(updates, uiSettings, isInstallingUpdate) => {
const {
isPopulated,
error,
items
} = updates;
return {
isPopulated,
error,
items,
isInstallingUpdate,
shortDateFormat: uiSettings.shortDateFormat
};
}
);
}
const mapDispatchToProps = {
fetchUpdates,
executeCommand
};
class UpdatesConnector extends Component {
//
// Lifecycle
componentDidMount() {
this.props.fetchUpdates();
}
//
// Listeners
onInstallLatestPress = () => {
this.props.executeCommand({ name: commandNames.APPLICATION_UPDATE });
}
//
// Render
render() {
return (
<Updates
onInstallLatestPress={this.onInstallLatestPress}
{...this.props}
/>
);
}
}
UpdatesConnector.propTypes = {
fetchUpdates: PropTypes.func.isRequired,
executeCommand: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(UpdatesConnector);