+
\\^$.|?*+()[{ have special meanings and need escaping with a \\
' }} />
+ {'More details'} {'Here'}
+
+
+ {'Regular expressions can be tested '}
+ Here
+
+
+ }
+
+
+
+ Name
+
+
+
+
+
+ {
+ fields && fields.map((field) => {
+ return (
+
+ );
+ })
+ }
+
+
+
+ Negate
+
+
+
+
+
+
+
+ Required
+
+
+
+
+
+
+
+ {
+ id &&
+
+ }
+
+
+
+
+ Save
+
+
+
+ );
+}
+
+EditSpecificationModalContent.propTypes = {
+ advancedSettings: PropTypes.bool.isRequired,
+ item: PropTypes.object.isRequired,
+ onInputChange: PropTypes.func.isRequired,
+ onFieldChange: PropTypes.func.isRequired,
+ onCancelPress: PropTypes.func.isRequired,
+ onSavePress: PropTypes.func.isRequired,
+ onDeleteSpecificationPress: PropTypes.func
+};
+
+export default EditSpecificationModalContent;
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContentConnector.js b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContentConnector.js
new file mode 100644
index 000000000..b56993dfb
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/EditSpecificationModalContentConnector.js
@@ -0,0 +1,78 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import { connect } from 'react-redux';
+import { createSelector } from 'reselect';
+import { clearCustomFormatSpecificationPending, saveCustomFormatSpecification, setCustomFormatSpecificationFieldValue, setCustomFormatSpecificationValue } from 'Store/Actions/settingsActions';
+import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
+import EditSpecificationModalContent from './EditSpecificationModalContent';
+
+function createMapStateToProps() {
+ return createSelector(
+ (state) => state.settings.advancedSettings,
+ createProviderSettingsSelector('customFormatSpecifications'),
+ (advancedSettings, specification) => {
+ return {
+ advancedSettings,
+ ...specification
+ };
+ }
+ );
+}
+
+const mapDispatchToProps = {
+ setCustomFormatSpecificationValue,
+ setCustomFormatSpecificationFieldValue,
+ saveCustomFormatSpecification,
+ clearCustomFormatSpecificationPending
+};
+
+class EditSpecificationModalContentConnector extends Component {
+
+ //
+ // Listeners
+
+ onInputChange = ({ name, value }) => {
+ this.props.setCustomFormatSpecificationValue({ name, value });
+ };
+
+ onFieldChange = ({ name, value }) => {
+ this.props.setCustomFormatSpecificationFieldValue({ name, value });
+ };
+
+ onCancelPress = () => {
+ this.props.clearCustomFormatSpecificationPending();
+ this.props.onModalClose();
+ };
+
+ onSavePress = () => {
+ this.props.saveCustomFormatSpecification({ id: this.props.id });
+ this.props.onModalClose();
+ };
+
+ //
+ // Render
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+EditSpecificationModalContentConnector.propTypes = {
+ id: PropTypes.number,
+ item: PropTypes.object.isRequired,
+ setCustomFormatSpecificationValue: PropTypes.func.isRequired,
+ setCustomFormatSpecificationFieldValue: PropTypes.func.isRequired,
+ clearCustomFormatSpecificationPending: PropTypes.func.isRequired,
+ saveCustomFormatSpecification: PropTypes.func.isRequired,
+ onModalClose: PropTypes.func.isRequired
+};
+
+export default connect(createMapStateToProps, mapDispatchToProps)(EditSpecificationModalContentConnector);
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.css b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.css
new file mode 100644
index 000000000..f05c942b0
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.css
@@ -0,0 +1,38 @@
+.customFormat {
+ composes: card from '~Components/Card.css';
+
+ width: 300px;
+}
+
+.nameContainer {
+ display: flex;
+ justify-content: space-between;
+}
+
+.name {
+ @add-mixin truncate;
+
+ margin-bottom: 20px;
+ font-weight: 300;
+ font-size: 24px;
+}
+
+.cloneButton {
+ composes: button from '~Components/Link/IconButton.css';
+
+ height: 36px;
+}
+
+.labels {
+ display: flex;
+ flex-wrap: wrap;
+ margin-top: 5px;
+ pointer-events: all;
+}
+
+.tooltipLabel {
+ composes: label from '~Components/Label.css';
+
+ margin: 0;
+ border: none;
+}
diff --git a/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.js b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.js
new file mode 100644
index 000000000..5a75cb0fd
--- /dev/null
+++ b/frontend/src/Settings/CustomFormats/CustomFormats/Specifications/Specification.js
@@ -0,0 +1,139 @@
+import PropTypes from 'prop-types';
+import React, { Component } from 'react';
+import Card from 'Components/Card';
+import Label from 'Components/Label';
+import IconButton from 'Components/Link/IconButton';
+import ConfirmModal from 'Components/Modal/ConfirmModal';
+import { icons, kinds } from 'Helpers/Props';
+import EditSpecificationModalConnector from './EditSpecificationModal';
+import styles from './Specification.css';
+
+class Specification extends Component {
+
+ //
+ // Lifecycle
+
+ constructor(props, context) {
+ super(props, context);
+
+ this.state = {
+ isEditSpecificationModalOpen: false,
+ isDeleteSpecificationModalOpen: false
+ };
+ }
+
+ //
+ // Listeners
+
+ onEditSpecificationPress = () => {
+ this.setState({ isEditSpecificationModalOpen: true });
+ };
+
+ onEditSpecificationModalClose = () => {
+ this.setState({ isEditSpecificationModalOpen: false });
+ };
+
+ onDeleteSpecificationPress = () => {
+ this.setState({
+ isEditSpecificationModalOpen: false,
+ isDeleteSpecificationModalOpen: true
+ });
+ };
+
+ onDeleteSpecificationModalClose = () => {
+ this.setState({ isDeleteSpecificationModalOpen: false });
+ };
+
+ onCloneSpecificationPress = () => {
+ this.props.onCloneSpecificationPress(this.props.id);
+ };
+
+ onConfirmDeleteSpecification = () => {
+ this.props.onConfirmDeleteSpecification(this.props.id);
+ };
+
+ //
+ // Lifecycle
+
+ render() {
+ const {
+ id,
+ implementationName,
+ name,
+ required,
+ negate
+ } = this.props;
+
+ return (
+
+
+
+
+
+
+ {
+ negate &&
+
+ }
+
+ {
+ required &&
+
+ }
+
+
+
+
+
+
+ );
+ }
+}
+
+Specification.propTypes = {
+ id: PropTypes.number.isRequired,
+ implementation: PropTypes.string.isRequired,
+ implementationName: PropTypes.string.isRequired,
+ name: PropTypes.string.isRequired,
+ negate: PropTypes.bool.isRequired,
+ required: PropTypes.bool.isRequired,
+ fields: PropTypes.arrayOf(PropTypes.object).isRequired,
+ onConfirmDeleteSpecification: PropTypes.func.isRequired,
+ onCloneSpecificationPress: PropTypes.func.isRequired
+};
+
+export default Specification;
diff --git a/frontend/src/Settings/MediaManagement/MediaManagement.js b/frontend/src/Settings/MediaManagement/MediaManagement.js
index d190dd9f6..4efada0cf 100644
--- a/frontend/src/Settings/MediaManagement/MediaManagement.js
+++ b/frontend/src/Settings/MediaManagement/MediaManagement.js
@@ -261,11 +261,11 @@ class MediaManagement extends Component {
name="downloadPropersAndRepacks"
helpTexts={[
'Whether or not to automatically upgrade to Propers/Repacks',
- 'Use \'Do not Prefer\' to sort by preferred word score over propers/repacks'
+ 'Use \'Do not Prefer\' to sort by custom format score over propers/repacks'
]}
helpTextWarning={
settings.downloadPropersAndRepacks.value === 'doNotPrefer' ?
- 'Use preferred words for automatic upgrades to propers/repacks' :
+ 'Use custom formats for automatic upgrades to propers/repacks' :
undefined
}
values={downloadPropersAndRepacksOptions}
diff --git a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js
index 01f101e0a..48d2c7be8 100644
--- a/frontend/src/Settings/MediaManagement/Naming/NamingModal.js
+++ b/frontend/src/Settings/MediaManagement/Naming/NamingModal.js
@@ -107,7 +107,7 @@ const mediaInfoTokens = [
const otherTokens = [
{ token: '{Release Group}', example: 'Rls Grp' },
- { token: '{Preferred Words}', example: 'iNTERNAL' }
+ { token: '{Custom Formats}', example: 'iNTERNAL' }
];
const originalTokens = [
diff --git a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.css b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.css
index 2f6589933..586f99e70 100644
--- a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.css
+++ b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.css
@@ -3,7 +3,8 @@
flex-wrap: wrap;
}
-.formGroupWrapper {
+.formGroupWrapper,
+.formatItemLarge {
flex: 0 0 calc($formGroupSmallWidth - 100px);
}
@@ -11,8 +12,20 @@
margin-right: auto;
}
-@media only screen and (max-width: $breakpointLarge) {
+.formatItemSmall {
+ display: none;
+}
+
+@media only screen and (max-width: calc($breakpointLarge + 100px)) {
.formGroupsContainer {
display: block;
}
+
+ .formatItemSmall {
+ display: block;
+ }
+
+ .formatItemLarge {
+ display: none;
+ }
}
diff --git a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
index b8fc66ffc..c42a1e3e6 100644
--- a/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
+++ b/frontend/src/Settings/Profiles/Quality/EditQualityProfileModalContent.js
@@ -14,11 +14,23 @@ import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import dimensions from 'Styles/Variables/dimensions';
+import QualityProfileFormatItems from './QualityProfileFormatItems';
import QualityProfileItems from './QualityProfileItems';
import styles from './EditQualityProfileModalContent.css';
const MODAL_BODY_PADDING = parseInt(dimensions.modalBodyPadding);
+function getCustomFormatRender(formatItems, otherProps) {
+ return (
+
+ );
+}
+
class EditQualityProfileModalContent extends Component {
//
@@ -92,6 +104,7 @@ class EditQualityProfileModalContent extends Component {
isSaving,
saveError,
qualities,
+ customFormats,
item,
isInUse,
onInputChange,
@@ -107,7 +120,10 @@ class EditQualityProfileModalContent extends Component {
name,
upgradeAllowed,
cutoff,
- items
+ minFormatScore,
+ cutoffFormatScore,
+ items,
+ formatItems
} = item;
return (
@@ -189,6 +205,44 @@ class EditQualityProfileModalContent extends Component {
/>
}
+
+ {
+ formatItems.value.length > 0 &&
+
+
+ Minimum Custom Format Score
+
+
+
+
+ }
+
+ {
+ upgradeAllowed.value && formatItems.value.length > 0 &&
+
+
+ Upgrade Until Custom Format Score
+
+
+
+
+ }
+
+
+ {getCustomFormatRender(formatItems, ...otherProps)}
+
@@ -200,6 +254,10 @@ class EditQualityProfileModalContent extends Component {
{...otherProps}
/>
+
+
+ {getCustomFormatRender(formatItems, otherProps)}
+