Sort movie files on movie details page

(cherry picked from commit 113b0864b8e92b7b768acc8341bdf4c9e2e1a47f)
This commit is contained in:
Mark McDowall 2023-10-06 12:38:10 -07:00 committed by Bogdan
parent 4a9c0b2240
commit b08981dee0
4 changed files with 79 additions and 51 deletions

View File

@ -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
};

View File

@ -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);

View File

@ -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);

View File

@ -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());