New: Release Profiles, Frontend updates (#580)

* New: Release Profiles - UI Updates

* New: Release Profiles - API Changes

* New: Release Profiles - Test Updates

* New: Release Profiles - Backend Updates

* New: Interactive Artist Search

* New: Change Montiored on Album Details Page

* New: Show Duration on Album Details Page

* Fixed: Manual Import not working if no albums are Missing

* Fixed: Sort search input by sortTitle

* Fixed: Queue columnLabel throwing JS error
This commit is contained in:
Qstick
2019-02-23 17:39:11 -05:00
committed by GitHub
parent f126eafd26
commit 3f064c94b9
409 changed files with 6882 additions and 3176 deletions
@@ -23,6 +23,7 @@ function EditRemotePathMappingModalContent(props) {
isSaving,
saveError,
item,
downloadClientHosts,
onInputChange,
onSavePress,
onModalClose,
@@ -55,17 +56,16 @@ function EditRemotePathMappingModalContent(props) {
{
!isFetching && !error &&
<Form
{...otherProps}
>
<Form {...otherProps}>
<FormGroup>
<FormLabel>Host</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
type={inputTypes.AUTO_COMPLETE}
name="host"
helpText="The same host you specified for the remote Download Client"
{...host}
values={downloadClientHosts}
onChange={onInputChange}
/>
</FormGroup>
@@ -140,6 +140,7 @@ EditRemotePathMappingModalContent.propTypes = {
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.shape(remotePathMappingShape).isRequired,
downloadClientHosts: PropTypes.arrayOf(PropTypes.string).isRequired,
onInputChange: PropTypes.func.isRequired,
onSavePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired,
@@ -13,11 +13,29 @@ const newRemotePathMapping = {
localPath: ''
};
const selectDownloadClientHosts = createSelector(
(state) => state.settings.downloadClients.items,
(downloadClients) => {
return downloadClients.reduce((acc, downloadClient) => {
const host = downloadClient.fields.find((field) => {
return field.name === 'host';
});
if (host && !acc.includes(host.value)) {
acc.push(host.value);
}
return acc;
}, []);
}
);
function createRemotePathMappingSelector() {
return createSelector(
(state, { id }) => id,
(state) => state.settings.remotePathMappings,
(id, remotePathMappings) => {
selectDownloadClientHosts,
(id, remotePathMappings, downloadClientHosts) => {
const {
isFetching,
error,
@@ -37,7 +55,8 @@ function createRemotePathMappingSelector() {
isSaving,
saveError,
item: settings.settings,
...settings
...settings,
downloadClientHosts
};
}
);
@@ -55,8 +74,8 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
setRemotePathMappingValue,
saveRemotePathMapping
dispatchSetRemotePathMappingValue: setRemotePathMappingValue,
dispatchSaveRemotePathMapping: saveRemotePathMapping
};
class EditRemotePathMappingModalContentConnector extends Component {
@@ -67,7 +86,7 @@ class EditRemotePathMappingModalContentConnector extends Component {
componentDidMount() {
if (!this.props.id) {
Object.keys(newRemotePathMapping).forEach((name) => {
this.props.setRemotePathMappingValue({
this.props.dispatchSetRemotePathMappingValue({
name,
value: newRemotePathMapping[name]
});
@@ -85,11 +104,11 @@ class EditRemotePathMappingModalContentConnector extends Component {
// Listeners
onInputChange = ({ name, value }) => {
this.props.setRemotePathMappingValue({ name, value });
this.props.dispatchSetRemotePathMappingValue({ name, value });
}
onSavePress = () => {
this.props.saveRemotePathMapping({ id: this.props.id });
this.props.dispatchSaveRemotePathMapping({ id: this.props.id });
}
//
@@ -111,8 +130,8 @@ EditRemotePathMappingModalContentConnector.propTypes = {
isSaving: PropTypes.bool.isRequired,
saveError: PropTypes.object,
item: PropTypes.object.isRequired,
setRemotePathMappingValue: PropTypes.func.isRequired,
saveRemotePathMapping: PropTypes.func.isRequired,
dispatchSetRemotePathMappingValue: PropTypes.func.isRequired,
dispatchSaveRemotePathMapping: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
@@ -8,11 +8,15 @@
}
.host {
flex: 0 0 300px;
@add-mixin truncate;
flex: 0 1 300px;
}
.path {
flex: 0 0 400px;
@add-mixin truncate;
flex: 0 1 400px;
}
.actions {
@@ -5,11 +5,15 @@
}
.host {
flex: 0 0 300px;
@add-mixin truncate;
flex: 0 1 300px;
}
.path {
flex: 0 0 400px;
@add-mixin truncate;
flex: 0 1 400px;
}
.addRemotePathMapping {
@@ -17,8 +17,8 @@ function createMapStateToProps() {
}
const mapDispatchToProps = {
fetchRemotePathMappings,
deleteRemotePathMapping
dispatchFetchRemotePathMappings: fetchRemotePathMappings,
dispatchDeleteRemotePathMapping: deleteRemotePathMapping
};
class RemotePathMappingsConnector extends Component {
@@ -27,14 +27,14 @@ class RemotePathMappingsConnector extends Component {
// Lifecycle
componentDidMount() {
this.props.fetchRemotePathMappings();
this.props.dispatchFetchRemotePathMappings();
}
//
// Listeners
onConfirmDeleteRemotePathMapping = (id) => {
this.props.deleteRemotePathMapping({ id });
this.props.dispatchDeleteRemotePathMapping({ id });
}
//
@@ -52,8 +52,8 @@ class RemotePathMappingsConnector extends Component {
}
RemotePathMappingsConnector.propTypes = {
fetchRemotePathMappings: PropTypes.func.isRequired,
deleteRemotePathMapping: PropTypes.func.isRequired
dispatchFetchRemotePathMappings: PropTypes.func.isRequired,
dispatchDeleteRemotePathMapping: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(RemotePathMappingsConnector);