New: UI Updates (Backup Restore in App, Profile Cloning)

UI Pulls from Sonarr
This commit is contained in:
Qstick
2018-01-14 17:11:37 -05:00
parent 80a5701b99
commit 744742b5ff
80 changed files with 2376 additions and 795 deletions
@@ -67,7 +67,7 @@ class EditLanguageProfileModalContentConnector extends Component {
}
componentDidMount() {
if (!this.props.id) {
if (!this.props.id && !this.props.isPopulated) {
this.props.fetchLanguageProfileSchema();
}
}
@@ -176,6 +176,7 @@ class EditLanguageProfileModalContentConnector extends Component {
EditLanguageProfileModalContentConnector.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
@@ -4,6 +4,11 @@
width: 300px;
}
.nameContainer {
display: flex;
justify-content: space-between;
}
.name {
@add-mixin truncate;
@@ -12,8 +17,15 @@
font-size: 24px;
}
.cloneButton {
composes: button from 'Components/Link/IconButton.css';
height: 36px;
}
.languages {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
pointer-events: all;
}
@@ -1,8 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds } from 'Helpers/Props';
import { icons, kinds } from 'Helpers/Props';
import Card from 'Components/Card';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import EditLanguageProfileModalConnector from './EditLanguageProfileModalConnector';
import styles from './LanguageProfile.css';
@@ -47,6 +48,15 @@ class LanguageProfile extends Component {
this.props.onConfirmDeleteLanguageProfile(this.props.id);
}
onCloneLanguageProfilePress = () => {
const {
id,
onCloneLanguageProfilePress
} = this.props;
onCloneLanguageProfilePress(id);
}
//
// Render
@@ -62,10 +72,20 @@ class LanguageProfile extends Component {
return (
<Card
className={styles.languageProfile}
overlayContent={true}
onPress={this.onEditLanguageProfilePress}
>
<div className={styles.name}>
{name}
<div className={styles.nameContainer}>
<div className={styles.name}>
{name}
</div>
<IconButton
className={styles.cloneButton}
title="Clone Profile"
name={icons.CLONE}
onPress={this.onCloneLanguageProfilePress}
/>
</div>
<div className={styles.languages}>
@@ -118,7 +138,8 @@ LanguageProfile.propTypes = {
cutoff: PropTypes.object.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
onCloneLanguageProfilePress: PropTypes.func.isRequired
};
export default LanguageProfile;
@@ -26,6 +26,11 @@ class LanguageProfiles extends Component {
//
// Listeners
onCloneLanguageProfilePress = (id) => {
this.props.onCloneLanguageProfilePress(id);
this.setState({ isLanguageProfileModalOpen: true });
}
onEditLanguageProfilePress = () => {
this.setState({ isLanguageProfileModalOpen: true });
}
@@ -62,6 +67,7 @@ class LanguageProfiles extends Component {
{...item}
isDeleting={isDeleting}
onConfirmDeleteLanguageProfile={onConfirmDeleteLanguageProfile}
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
/>
);
})
@@ -96,7 +102,8 @@ LanguageProfiles.propTypes = {
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired
onConfirmDeleteLanguageProfile: PropTypes.func.isRequired,
onCloneLanguageProfilePress: PropTypes.func.isRequired
};
export default LanguageProfiles;
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchLanguageProfiles, deleteLanguageProfile } from 'Store/Actions/settingsActions';
import { fetchLanguageProfiles, deleteLanguageProfile, cloneLanguageProfile } from 'Store/Actions/settingsActions';
import LanguageProfiles from './LanguageProfiles';
function createMapStateToProps() {
@@ -19,8 +19,9 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
fetchLanguageProfiles,
deleteLanguageProfile
dispatchFetchLanguageProfiles: fetchLanguageProfiles,
dispatchDeleteLanguageProfile: deleteLanguageProfile,
dispatchCloneLanguageProfile: cloneLanguageProfile
};
class LanguageProfilesConnector extends Component {
@@ -29,14 +30,18 @@ class LanguageProfilesConnector extends Component {
// Lifecycle
componentDidMount() {
this.props.fetchLanguageProfiles();
this.props.dispatchFetchLanguageProfiles();
}
//
// Listeners
onConfirmDeleteLanguageProfile = (id) => {
this.props.deleteLanguageProfile({ id });
this.props.dispatchDeleteLanguageProfile({ id });
}
onCloneLanguageProfilePress = (id) => {
this.props.dispatchCloneLanguageProfile({ id });
}
//
@@ -46,6 +51,7 @@ class LanguageProfilesConnector extends Component {
return (
<LanguageProfiles
onConfirmDeleteLanguageProfile={this.onConfirmDeleteLanguageProfile}
onCloneLanguageProfilePress={this.onCloneLanguageProfilePress}
{...this.props}
/>
);
@@ -53,8 +59,9 @@ class LanguageProfilesConnector extends Component {
}
LanguageProfilesConnector.propTypes = {
fetchLanguageProfiles: PropTypes.func.isRequired,
deleteLanguageProfile: PropTypes.func.isRequired
dispatchFetchLanguageProfiles: PropTypes.func.isRequired,
dispatchDeleteLanguageProfile: PropTypes.func.isRequired,
dispatchCloneLanguageProfile: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(LanguageProfilesConnector);
@@ -92,7 +92,7 @@ class EditMetadataProfileModalContentConnector extends Component {
}
componentDidMount() {
if (!this.props.id) {
if (!this.props.id && !this.props.isPopulated) {
this.props.fetchMetadataProfileSchema();
}
}
@@ -162,6 +162,7 @@ class EditMetadataProfileModalContentConnector extends Component {
EditMetadataProfileModalContentConnector.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
@@ -4,6 +4,11 @@
width: 300px;
}
.nameContainer {
display: flex;
justify-content: space-between;
}
.name {
@add-mixin truncate;
@@ -12,8 +17,15 @@
font-size: 24px;
}
.cloneButton {
composes: button from 'Components/Link/IconButton.css';
height: 36px;
}
.albumTypes {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
pointer-events: all;
}
@@ -1,8 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds } from 'Helpers/Props';
import { icons, kinds } from 'Helpers/Props';
import Card from 'Components/Card';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import EditMetadataProfileModalConnector from './EditMetadataProfileModalConnector';
import styles from './MetadataProfile.css';
@@ -47,6 +48,17 @@ class MetadataProfile extends Component {
this.props.onConfirmDeleteMetadataProfile(this.props.id);
}
onCloneMetadataProfilePress = () => {
const {
id,
onCloneMetadataProfilePress
} = this.props;
onCloneMetadataProfilePress(id);
}
//
// Render
@@ -62,10 +74,20 @@ class MetadataProfile extends Component {
return (
<Card
className={styles.metadataProfile}
overlayContent={true}
onPress={this.onEditMetadataProfilePress}
>
<div className={styles.name}>
{name}
<div className={styles.nameContainer}>
<div className={styles.name}>
{name}
</div>
<IconButton
className={styles.cloneButton}
title="Clone Profile"
name={icons.CLONE}
onPress={this.onCloneMetadataProfilePress}
/>
</div>
<div className={styles.albumTypes}>
@@ -136,7 +158,9 @@ MetadataProfile.propTypes = {
primaryAlbumTypes: PropTypes.arrayOf(PropTypes.object).isRequired,
secondaryAlbumTypes: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteMetadataProfile: PropTypes.func.isRequired
onConfirmDeleteMetadataProfile: PropTypes.func.isRequired,
onCloneMetadataProfilePress: PropTypes.func.isRequired
};
export default MetadataProfile;
@@ -26,6 +26,11 @@ class MetadataProfiles extends Component {
//
// Listeners
onCloneMetadataProfilePress = (id) => {
this.props.onCloneMetadataProfilePress(id);
this.setState({ isMetadataProfileModalOpen: true });
}
onEditMetadataProfilePress = () => {
this.setState({ isMetadataProfileModalOpen: true });
}
@@ -62,6 +67,7 @@ class MetadataProfiles extends Component {
{...item}
isDeleting={isDeleting}
onConfirmDeleteMetadataProfile={onConfirmDeleteMetadataProfile}
onCloneMetadataProfilePress={this.onCloneMetadataProfilePress}
/>
);
})
@@ -96,7 +102,8 @@ MetadataProfiles.propTypes = {
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteMetadataProfile: PropTypes.func.isRequired
onConfirmDeleteMetadataProfile: PropTypes.func.isRequired,
onCloneMetadataProfilePress: PropTypes.func.isRequired
};
export default MetadataProfiles;
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchMetadataProfiles, deleteMetadataProfile } from 'Store/Actions/settingsActions';
import { fetchMetadataProfiles, deleteMetadataProfile, cloneMetadataProfile } from 'Store/Actions/settingsActions';
import MetadataProfiles from './MetadataProfiles';
function createMapStateToProps() {
@@ -19,8 +19,9 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
fetchMetadataProfiles,
deleteMetadataProfile
dispatchFetchMetadataProfiles: fetchMetadataProfiles,
dispatchDeleteMetadataProfile: deleteMetadataProfile,
dispatchCloneMetadataProfile: cloneMetadataProfile
};
class MetadataProfilesConnector extends Component {
@@ -29,14 +30,18 @@ class MetadataProfilesConnector extends Component {
// Lifecycle
componentDidMount() {
this.props.fetchMetadataProfiles();
this.props.dispatchFetchMetadataProfiles();
}
//
// Listeners
onConfirmDeleteMetadataProfile = (id) => {
this.props.deleteMetadataProfile({ id });
this.props.dispatchDeleteMetadataProfile({ id });
}
onCloneMetadataProfilePress = (id) => {
this.props.dispatchCloneMetadataProfile({ id });
}
//
@@ -46,6 +51,7 @@ class MetadataProfilesConnector extends Component {
return (
<MetadataProfiles
onConfirmDeleteMetadataProfile={this.onConfirmDeleteMetadataProfile}
onCloneMetadataProfilePress={this.onCloneMetadataProfilePress}
{...this.props}
/>
);
@@ -53,8 +59,9 @@ class MetadataProfilesConnector extends Component {
}
MetadataProfilesConnector.propTypes = {
fetchMetadataProfiles: PropTypes.func.isRequired,
deleteMetadataProfile: PropTypes.func.isRequired
dispatchFetchMetadataProfiles: PropTypes.func.isRequired,
dispatchDeleteMetadataProfile: PropTypes.func.isRequired,
dispatchCloneMetadataProfile: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(MetadataProfilesConnector);
@@ -94,12 +94,12 @@ class EditQualityProfileModalContentConnector extends Component {
dragQualityIndex: null,
dropQualityIndex: null,
dropPosition: null,
editGroups: true
editGroups: false
};
}
componentDidMount() {
if (!this.props.id) {
if (!this.props.id && !this.props.isPopulated) {
this.props.fetchQualityProfileSchema();
}
}
@@ -429,6 +429,7 @@ class EditQualityProfileModalContentConnector extends Component {
EditQualityProfileModalContentConnector.propTypes = {
id: PropTypes.number,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
@@ -4,6 +4,11 @@
width: 300px;
}
.nameContainer {
display: flex;
justify-content: space-between;
}
.name {
@add-mixin truncate;
@@ -12,10 +17,17 @@
font-size: 24px;
}
.cloneButton {
composes: button from 'Components/Link/IconButton.css';
height: 36px;
}
.qualities {
display: flex;
flex-wrap: wrap;
margin-top: 5px;
pointer-events: all;
}
.tooltipLabel {
@@ -1,8 +1,9 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { kinds, tooltipPositions } from 'Helpers/Props';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import Card from 'Components/Card';
import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import Tooltip from 'Components/Tooltip/Tooltip';
import EditQualityProfileModalConnector from './EditQualityProfileModalConnector';
@@ -48,6 +49,17 @@ class QualityProfile extends Component {
this.props.onConfirmDeleteQualityProfile(this.props.id);
}
onCloneQualityProfilePress = () => {
const {
id,
onCloneQualityProfilePress
} = this.props;
onCloneQualityProfilePress(id);
}
//
// Render
@@ -63,10 +75,20 @@ class QualityProfile extends Component {
return (
<Card
className={styles.qualityProfile}
overlayContent={true}
onPress={this.onEditQualityProfilePress}
>
<div className={styles.name}>
{name}
<div className={styles.nameContainer}>
<div className={styles.name}>
{name}
</div>
<IconButton
className={styles.cloneButton}
title="Clone Profile"
name={icons.CLONE}
onPress={this.onCloneQualityProfilePress}
/>
</div>
<div className={styles.qualities}>
@@ -157,7 +179,8 @@ QualityProfile.propTypes = {
cutoff: PropTypes.number.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
isDeleting: PropTypes.bool.isRequired,
onConfirmDeleteQualityProfile: PropTypes.func.isRequired
onConfirmDeleteQualityProfile: PropTypes.func.isRequired,
onCloneQualityProfilePress: PropTypes.func.isRequired
};
export default QualityProfile;
@@ -25,10 +25,6 @@ class QualityProfileItems extends Component {
};
}
componentDidMount() {
this.props.onToggleEditGroupsMode();
}
//
// Listeners
@@ -26,6 +26,11 @@ class QualityProfiles extends Component {
//
// Listeners
onCloneQualityProfilePress = (id) => {
this.props.onCloneQualityProfilePress(id);
this.setState({ isQualityProfileModalOpen: true });
}
onEditQualityProfilePress = () => {
this.setState({ isQualityProfileModalOpen: true });
}
@@ -51,7 +56,7 @@ class QualityProfiles extends Component {
>
<PageSectionContent
errorMessage="Unable to load Quality Profiles"
{...otherProps}
{...otherProps}c={true}
>
<div className={styles.qualityProfiles}>
{
@@ -62,6 +67,7 @@ class QualityProfiles extends Component {
{...item}
isDeleting={isDeleting}
onConfirmDeleteQualityProfile={onConfirmDeleteQualityProfile}
onCloneQualityProfilePress={this.onCloneQualityProfilePress}
/>
);
})
@@ -95,7 +101,8 @@ QualityProfiles.propTypes = {
error: PropTypes.object,
isDeleting: PropTypes.bool.isRequired,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteQualityProfile: PropTypes.func.isRequired
onConfirmDeleteQualityProfile: PropTypes.func.isRequired,
onCloneQualityProfilePress: PropTypes.func.isRequired
};
export default QualityProfiles;
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchQualityProfiles, deleteQualityProfile } from 'Store/Actions/settingsActions';
import { fetchQualityProfiles, deleteQualityProfile, cloneQualityProfile } from 'Store/Actions/settingsActions';
import QualityProfiles from './QualityProfiles';
function createMapStateToProps() {
@@ -17,8 +17,9 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
fetchQualityProfiles,
deleteQualityProfile
dispatchFetchQualityProfiles: fetchQualityProfiles,
dispatchDeleteQualityProfile: deleteQualityProfile,
dispatchCloneQualityProfile: cloneQualityProfile
};
class QualityProfilesConnector extends Component {
@@ -27,14 +28,18 @@ class QualityProfilesConnector extends Component {
// Lifecycle
componentDidMount() {
this.props.fetchQualityProfiles();
this.props.dispatchFetchQualityProfiles();
}
//
// Listeners
onConfirmDeleteQualityProfile = (id) => {
this.props.deleteQualityProfile({ id });
this.props.dispatchDeleteQualityProfile({ id });
}
onCloneQualityProfilePress = (id) => {
this.props.dispatchCloneQualityProfile({ id });
}
//
@@ -44,6 +49,7 @@ class QualityProfilesConnector extends Component {
return (
<QualityProfiles
onConfirmDeleteQualityProfile={this.onConfirmDeleteQualityProfile}
onCloneQualityProfilePress={this.onCloneQualityProfilePress}
{...this.props}
/>
);
@@ -51,8 +57,9 @@ class QualityProfilesConnector extends Component {
}
QualityProfilesConnector.propTypes = {
fetchQualityProfiles: PropTypes.func.isRequired,
deleteQualityProfile: PropTypes.func.isRequired
dispatchFetchQualityProfiles: PropTypes.func.isRequired,
dispatchDeleteQualityProfile: PropTypes.func.isRequired,
dispatchCloneQualityProfile: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(QualityProfilesConnector);