mirror of
https://github.com/Radarr/Radarr.git
synced 2025-04-24 06:27:08 -04:00
Sort movie files on movie details page
(cherry picked from commit 113b0864b8e92b7b768acc8341bdf4c9e2e1a47f)
This commit is contained in:
parent
4a9c0b2240
commit
b08981dee0
4 changed files with 79 additions and 51 deletions
|
@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { sortDirections } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import MovieFileEditorRow from './MovieFileEditorRow';
|
||||
import styles from './MovieFileEditorTableContent.css';
|
||||
|
@ -15,6 +16,9 @@ class MovieFileEditorTableContent extends Component {
|
|||
const {
|
||||
items,
|
||||
columns,
|
||||
sortKey,
|
||||
sortDirection,
|
||||
onSortPress,
|
||||
onTableOptionChange
|
||||
} = this.props;
|
||||
|
||||
|
@ -31,6 +35,9 @@ class MovieFileEditorTableContent extends Component {
|
|||
!!items.length &&
|
||||
<Table
|
||||
columns={columns}
|
||||
sortKey={sortKey}
|
||||
sortDirection={sortDirection}
|
||||
onSortPress={onSortPress}
|
||||
onTableOptionChange={onTableOptionChange}
|
||||
>
|
||||
<TableBody>
|
||||
|
@ -60,7 +67,10 @@ MovieFileEditorTableContent.propTypes = {
|
|||
isDeleting: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
sortKey: PropTypes.string.isRequired,
|
||||
sortDirection: PropTypes.oneOf(sortDirections.all),
|
||||
onTableOptionChange: PropTypes.func.isRequired,
|
||||
onSortPress: PropTypes.func.isRequired,
|
||||
onDeletePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
|
|
@ -2,8 +2,9 @@ import PropTypes from 'prop-types';
|
|||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { deleteMovieFile, setMovieFilesTableOption, updateMovieFiles } from 'Store/Actions/movieFileActions';
|
||||
import { deleteMovieFile, setMovieFilesSort, setMovieFilesTableOption } from 'Store/Actions/movieFileActions';
|
||||
import { fetchLanguages, fetchQualityProfileSchema } from 'Store/Actions/settingsActions';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
||||
import getQualities from 'Utilities/Quality/getQualities';
|
||||
import MovieFileEditorTableContent from './MovieFileEditorTableContent';
|
||||
|
@ -11,7 +12,7 @@ import MovieFileEditorTableContent from './MovieFileEditorTableContent';
|
|||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { movieId }) => movieId,
|
||||
(state) => state.movieFiles,
|
||||
createClientSideCollectionSelector('movieFiles'),
|
||||
(state) => state.settings.languages,
|
||||
(state) => state.settings.qualityProfiles,
|
||||
createMovieSelector(),
|
||||
|
@ -28,6 +29,8 @@ function createMapStateToProps() {
|
|||
return {
|
||||
items: filesForMovie,
|
||||
columns: movieFiles.columns,
|
||||
sortKey: movieFiles.sortKey,
|
||||
sortDirection: movieFiles.sortDirection,
|
||||
isDeleting: movieFiles.isDeleting,
|
||||
isSaving: movieFiles.isSaving,
|
||||
error: null,
|
||||
|
@ -38,31 +41,13 @@ function createMapStateToProps() {
|
|||
);
|
||||
}
|
||||
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
dispatchFetchQualityProfileSchema() {
|
||||
dispatch(fetchQualityProfileSchema());
|
||||
},
|
||||
|
||||
dispatchFetchLanguages() {
|
||||
dispatch(fetchLanguages());
|
||||
},
|
||||
|
||||
dispatchUpdateMovieFiles(updateProps) {
|
||||
dispatch(updateMovieFiles(updateProps));
|
||||
},
|
||||
|
||||
onTableOptionChange(payload) {
|
||||
dispatch(setMovieFilesTableOption(payload));
|
||||
},
|
||||
|
||||
onDeletePress(movieFileId) {
|
||||
dispatch(deleteMovieFile({
|
||||
id: movieFileId
|
||||
}));
|
||||
}
|
||||
};
|
||||
}
|
||||
const mapDispatchToProps = {
|
||||
fetchQualityProfileSchema,
|
||||
fetchLanguages,
|
||||
deleteMovieFile,
|
||||
setMovieFilesTableOption,
|
||||
setMovieFilesSort
|
||||
};
|
||||
|
||||
class MovieFileEditorTableContentConnector extends Component {
|
||||
|
||||
|
@ -70,24 +55,40 @@ class MovieFileEditorTableContentConnector extends Component {
|
|||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
this.props.dispatchFetchLanguages();
|
||||
this.props.dispatchFetchQualityProfileSchema();
|
||||
this.props.fetchLanguages();
|
||||
this.props.fetchQualityProfileSchema();
|
||||
}
|
||||
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onDeletePress = (movieFileId) => {
|
||||
this.props.deleteMovieFile({
|
||||
id: movieFileId
|
||||
});
|
||||
};
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setMovieFilesTableOption(payload);
|
||||
};
|
||||
|
||||
onSortPress = (sortKey, sortDirection) => {
|
||||
this.props.setMovieFilesSort({
|
||||
sortKey,
|
||||
sortDirection
|
||||
});
|
||||
};
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
const {
|
||||
dispatchFetchLanguages,
|
||||
dispatchFetchQualityProfileSchema,
|
||||
dispatchUpdateMovieFiles,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
<MovieFileEditorTableContent
|
||||
{...otherProps}
|
||||
{...this.props}
|
||||
onDeletePress={this.onDeletePress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onSortPress={this.onSortPress}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
@ -97,9 +98,11 @@ MovieFileEditorTableContentConnector.propTypes = {
|
|||
movieId: PropTypes.number.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
qualities: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchFetchLanguages: PropTypes.func.isRequired,
|
||||
dispatchFetchQualityProfileSchema: PropTypes.func.isRequired,
|
||||
dispatchUpdateMovieFiles: PropTypes.func.isRequired
|
||||
fetchLanguages: PropTypes.func.isRequired,
|
||||
fetchQualityProfileSchema: PropTypes.func.isRequired,
|
||||
deleteMovieFile: PropTypes.func.isRequired,
|
||||
setMovieFilesTableOption: PropTypes.func.isRequired,
|
||||
setMovieFilesSort: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(MovieFileEditorTableContentConnector);
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(MovieFileEditorTableContentConnector);
|
||||
|
|
|
@ -4,8 +4,9 @@ import { createAction } from 'redux-actions';
|
|||
import { batchActions } from 'redux-batched-actions';
|
||||
import Icon from 'Components/Icon';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import { icons, sortDirections } from 'Helpers/Props';
|
||||
import movieEntities from 'Movie/movieEntities';
|
||||
import createSetClientSideCollectionSortReducer from 'Store/Actions/Creators/Reducers/createSetClientSideCollectionSortReducer';
|
||||
import createSetTableOptionReducer from 'Store/Actions/Creators/Reducers/createSetTableOptionReducer';
|
||||
import { createThunk, handleThunks } from 'Store/thunks';
|
||||
import createAjaxRequest from 'Utilities/createAjaxRequest';
|
||||
|
@ -31,13 +32,16 @@ export const defaultState = {
|
|||
deleteError: null,
|
||||
isSaving: false,
|
||||
saveError: null,
|
||||
sortKey: 'relativePath',
|
||||
sortDirection: sortDirections.ASCENDING,
|
||||
items: [],
|
||||
|
||||
columns: [
|
||||
{
|
||||
name: 'relativePath',
|
||||
label: () => translate('RelativePath'),
|
||||
isVisible: true
|
||||
isVisible: true,
|
||||
isSortable: true
|
||||
},
|
||||
{
|
||||
name: 'videoCodec',
|
||||
|
@ -67,7 +71,8 @@ export const defaultState = {
|
|||
{
|
||||
name: 'size',
|
||||
label: () => translate('Size'),
|
||||
isVisible: true
|
||||
isVisible: true,
|
||||
isSortable: true
|
||||
},
|
||||
{
|
||||
name: 'languages',
|
||||
|
@ -96,12 +101,14 @@ export const defaultState = {
|
|||
name: icons.SCORE,
|
||||
title: () => translate('CustomFormatScore')
|
||||
}),
|
||||
isVisible: true
|
||||
isVisible: true,
|
||||
isSortable: true
|
||||
},
|
||||
{
|
||||
name: 'dateAdded',
|
||||
label: () => translate('Added'),
|
||||
isVisible: false
|
||||
isVisible: false,
|
||||
isSortable: true
|
||||
},
|
||||
{
|
||||
name: 'actions',
|
||||
|
@ -114,7 +121,9 @@ export const defaultState = {
|
|||
};
|
||||
|
||||
export const persistState = [
|
||||
'movieFiles.columns'
|
||||
'movieFiles.columns',
|
||||
'movieFiles.sortDirection',
|
||||
'movieFiles.sortKey'
|
||||
];
|
||||
|
||||
//
|
||||
|
@ -125,6 +134,7 @@ export const DELETE_MOVIE_FILE = 'movieFiles/deleteMovieFile';
|
|||
export const DELETE_MOVIE_FILES = 'movieFiles/deleteMovieFiles';
|
||||
export const UPDATE_MOVIE_FILES = 'movieFiles/updateMovieFiles';
|
||||
export const CLEAR_MOVIE_FILES = 'movieFiles/clearMovieFiles';
|
||||
export const SET_MOVIE_FILES_SORT = 'movieFiles/setMovieFilesSort';
|
||||
export const SET_MOVIE_FILES_TABLE_OPTION = 'movieFiles/setMovieFilesTableOption';
|
||||
|
||||
//
|
||||
|
@ -135,6 +145,7 @@ export const deleteMovieFile = createThunk(DELETE_MOVIE_FILE);
|
|||
export const deleteMovieFiles = createThunk(DELETE_MOVIE_FILES);
|
||||
export const updateMovieFiles = createThunk(UPDATE_MOVIE_FILES);
|
||||
export const clearMovieFiles = createAction(CLEAR_MOVIE_FILES);
|
||||
export const setMovieFilesSort = createAction(SET_MOVIE_FILES_SORT);
|
||||
export const setMovieFilesTableOption = createAction(SET_MOVIE_FILES_TABLE_OPTION);
|
||||
|
||||
//
|
||||
|
@ -327,6 +338,7 @@ export const actionHandlers = handleThunks({
|
|||
// Reducers
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_MOVIE_FILES_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[CLEAR_MOVIE_FILES]: (state) => {
|
||||
|
@ -340,6 +352,8 @@ export const reducers = createHandleActions({
|
|||
saveError: null,
|
||||
items: []
|
||||
});
|
||||
}
|
||||
},
|
||||
|
||||
[SET_MOVIE_FILES_SORT]: createSetClientSideCollectionSortReducer(section)
|
||||
|
||||
}, defaultState, section);
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Microsoft.AspNetCore.Mvc;
|
||||
using NzbDrone.Core.Extras.Files;
|
||||
using NzbDrone.Core.Extras.Metadata.Files;
|
||||
|
@ -27,9 +28,9 @@ namespace Radarr.Api.V3.ExtraFiles
|
|||
{
|
||||
var extraFiles = new List<ExtraFileResource>();
|
||||
|
||||
var subtitleFiles = _subtitleFileService.GetFilesByMovie(movieId);
|
||||
var metadataFiles = _metadataFileService.GetFilesByMovie(movieId);
|
||||
var otherExtraFiles = _otherFileService.GetFilesByMovie(movieId);
|
||||
var subtitleFiles = _subtitleFileService.GetFilesByMovie(movieId).OrderBy(f => f.RelativePath).ToList();
|
||||
var metadataFiles = _metadataFileService.GetFilesByMovie(movieId).OrderBy(f => f.RelativePath).ToList();
|
||||
var otherExtraFiles = _otherFileService.GetFilesByMovie(movieId).OrderBy(f => f.RelativePath).ToList();
|
||||
|
||||
extraFiles.AddRange(subtitleFiles.ToResource());
|
||||
extraFiles.AddRange(metadataFiles.ToResource());
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue