From d29e254dcb731f98c115105414b2100218e52560 Mon Sep 17 00:00:00 2001 From: Mark McDowall Date: Mon, 12 Apr 2021 22:15:59 -0700 Subject: [PATCH] New: File info scrolls on mobile Closes #4436 --- .../src/Episode/Summary/EpisodeFileRow.css | 20 ++ .../src/Episode/Summary/EpisodeFileRow.js | 179 ++++++++++++++++++ .../src/Episode/Summary/EpisodeSummary.css | 17 +- .../src/Episode/Summary/EpisodeSummary.js | 125 ++++++------ .../Summary/EpisodeSummaryConnector.js | 4 + 5 files changed, 277 insertions(+), 68 deletions(-) create mode 100644 frontend/src/Episode/Summary/EpisodeFileRow.css create mode 100644 frontend/src/Episode/Summary/EpisodeFileRow.js diff --git a/frontend/src/Episode/Summary/EpisodeFileRow.css b/frontend/src/Episode/Summary/EpisodeFileRow.css new file mode 100644 index 000000000..565a785f0 --- /dev/null +++ b/frontend/src/Episode/Summary/EpisodeFileRow.css @@ -0,0 +1,20 @@ +.size { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + width: 100px; +} + +.language, +.quality { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + width: 100px; +} + +.actions { + composes: cell from '~Components/Table/Cells/TableRowCell.css'; + + display: flex; + justify-content: flex-end; + width: 55px; +} diff --git a/frontend/src/Episode/Summary/EpisodeFileRow.js b/frontend/src/Episode/Summary/EpisodeFileRow.js new file mode 100644 index 000000000..03c2cc264 --- /dev/null +++ b/frontend/src/Episode/Summary/EpisodeFileRow.js @@ -0,0 +1,179 @@ +import PropTypes from 'prop-types'; +import React, { Component } from 'react'; +import formatBytes from 'Utilities/Number/formatBytes'; +import { icons, kinds, tooltipPositions } from 'Helpers/Props'; +import Icon from 'Components/Icon'; +import IconButton from 'Components/Link/IconButton'; +import ConfirmModal from 'Components/Modal/ConfirmModal'; +import TableRow from 'Components/Table/TableRow'; +import TableRowCell from 'Components/Table/Cells/TableRowCell'; +import Popover from 'Components/Tooltip/Popover'; +import EpisodeLanguage from 'Episode/EpisodeLanguage'; +import EpisodeQuality from 'Episode/EpisodeQuality'; +import MediaInfo from './MediaInfo'; +import styles from './EpisodeFileRow.css'; + +class EpisodeFileRow extends Component { + + // + // Lifecycle + + constructor(props, context) { + super(props, context); + + this.state = { + isRemoveEpisodeFileModalOpen: false + }; + } + + // + // Listeners + + onRemoveEpisodeFilePress = () => { + this.setState({ isRemoveEpisodeFileModalOpen: true }); + } + + onConfirmRemoveEpisodeFile = () => { + this.props.onDeleteEpisodeFile(); + + this.setState({ isRemoveEpisodeFileModalOpen: false }); + } + + onRemoveEpisodeFileModalClose = () => { + this.setState({ isRemoveEpisodeFileModalOpen: false }); + } + + // + // Render + + render() { + const { + path, + size, + language, + quality, + languageCutoffNotMet, + qualityCutoffNotMet, + mediaInfo, + columns + } = this.props; + + return ( + + { + columns.map((column) => { + const { + name, + isVisible + } = column; + + if (!isVisible) { + return null; + } + + if (name === 'path') { + return ( + + {path} + + ); + } + + if (name === 'size') { + return ( + + {formatBytes(size)} + + ); + } + + if (name === 'language') { + return ( + + + + ); + } + + if (name === 'quality') { + return ( + + + + ); + } + + if (name === 'actions') { + return ( + + { + mediaInfo ? + + } + title="Media Info" + body={} + position={tooltipPositions.LEFT} + /> : + null + } + + + + ); + } + + return null; + }) + } + + + + ); + } + +} + +EpisodeFileRow.propTypes = { + path: PropTypes.string.isRequired, + size: PropTypes.number.isRequired, + language: PropTypes.object.isRequired, + languageCutoffNotMet: PropTypes.bool.isRequired, + quality: PropTypes.object.isRequired, + qualityCutoffNotMet: PropTypes.bool.isRequired, + mediaInfo: PropTypes.object, + columns: PropTypes.arrayOf(PropTypes.object).isRequired, + onDeleteEpisodeFile: PropTypes.func.isRequired +}; + +export default EpisodeFileRow; diff --git a/frontend/src/Episode/Summary/EpisodeSummary.css b/frontend/src/Episode/Summary/EpisodeSummary.css index f8238ed8a..5a53e3c59 100644 --- a/frontend/src/Episode/Summary/EpisodeSummary.css +++ b/frontend/src/Episode/Summary/EpisodeSummary.css @@ -4,8 +4,12 @@ font-weight: bold; } -.overview, +.overview { + margin-top: 20px; +} + .files { + overflow-x: auto; margin-top: 20px; } @@ -25,9 +29,8 @@ } .path { - @add-mixin truncate; - flex: 1 0 1px; + white-space: nowrap !important; } .size, @@ -46,3 +49,11 @@ flex: 0 0 80px; } } + +@media only screen and (max-width: $breakpointSmall) { + .files { + overflow-y: hidden; + min-width: 100%; + width: 100%; + } +} diff --git a/frontend/src/Episode/Summary/EpisodeSummary.js b/frontend/src/Episode/Summary/EpisodeSummary.js index ef1b7cc67..b32e72fcb 100644 --- a/frontend/src/Episode/Summary/EpisodeSummary.js +++ b/frontend/src/Episode/Summary/EpisodeSummary.js @@ -1,18 +1,48 @@ import PropTypes from 'prop-types'; import React, { Component } from 'react'; -import formatBytes from 'Utilities/Number/formatBytes'; -import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props'; -import Icon from 'Components/Icon'; +import { kinds, sizes } from 'Helpers/Props'; import Label from 'Components/Label'; -import IconButton from 'Components/Link/IconButton'; import ConfirmModal from 'Components/Modal/ConfirmModal'; -import Popover from 'Components/Tooltip/Popover'; +import Table from 'Components/Table/Table'; +import TableBody from 'Components/Table/TableBody'; import QualityProfileNameConnector from 'Settings/Profiles/Quality/QualityProfileNameConnector'; -import EpisodeQuality from 'Episode/EpisodeQuality'; import EpisodeAiringConnector from './EpisodeAiringConnector'; -import MediaInfo from './MediaInfo'; +import EpisodeFileRow from './EpisodeFileRow'; import styles from './EpisodeSummary.css'; +const columns = [ + { + name: 'path', + label: 'Path', + isSortable: false, + isVisible: true + }, + { + name: 'size', + label: 'Size', + isSortable: false, + isVisible: true + }, + { + name: 'language', + label: 'Language', + isSortable: false, + isVisible: true + }, + { + name: 'quality', + label: 'Quality', + isSortable: false, + isVisible: true + }, + { + name: 'actions', + label: '', + isSortable: false, + isVisible: true + } +]; + class EpisodeSummary extends Component { // @@ -54,8 +84,11 @@ class EpisodeSummary extends Component { mediaInfo, path, size, + language, quality, - qualityCutoffNotMet + languageCutoffNotMet, + qualityCutoffNotMet, + onDeleteEpisodeFile } = this.props; const hasOverview = !!overview; @@ -93,63 +126,23 @@ class EpisodeSummary extends Component { { - path && -
-
-
- Path -
- -
- Size -
- -
- Quality -
- -
-
- -
-
- {path} -
- -
- {formatBytes(size)} -
- -
- -
- -
- - } - title="Media Info" - body={} - position={tooltipPositions.LEFT} - /> - - -
-
-
+ path ? + + + + +
: + null }