mirror of
https://github.com/Radarr/Radarr
synced 2025-12-07 08:54:57 +01:00
Convert Collection Footer to TypeScript
This commit is contained in:
parent
3a55316ada
commit
1d1aca1a04
6 changed files with 359 additions and 361 deletions
|
|
@ -20,7 +20,7 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||||
import CollectionFooter from './CollectionFooter';
|
import CollectionFooter from './CollectionFooter';
|
||||||
import CollectionFilterMenu from './Menus/CollectionFilterMenu';
|
import CollectionFilterMenu from './Menus/CollectionFilterMenu';
|
||||||
import CollectionSortMenu from './Menus/CollectionSortMenu';
|
import CollectionSortMenu from './Menus/CollectionSortMenu';
|
||||||
import NoCollection from './NoCollection';
|
import NoCollections from './NoCollections';
|
||||||
import CollectionOverviewsConnector from './Overview/CollectionOverviewsConnector';
|
import CollectionOverviewsConnector from './Overview/CollectionOverviewsConnector';
|
||||||
import CollectionOverviewOptionsModal from './Overview/Options/CollectionOverviewOptionsModal';
|
import CollectionOverviewOptionsModal from './Overview/Options/CollectionOverviewOptionsModal';
|
||||||
|
|
||||||
|
|
@ -341,7 +341,7 @@ class Collection extends Component {
|
||||||
|
|
||||||
{
|
{
|
||||||
!error && isPopulated && !items.length &&
|
!error && isPopulated && !items.length &&
|
||||||
<NoCollection totalItems={totalItems} />
|
<NoCollections totalItems={totalItems} />
|
||||||
}
|
}
|
||||||
</PageContentBody>
|
</PageContentBody>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,300 +0,0 @@
|
||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
|
||||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
|
||||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
|
||||||
import { inputTypes, kinds } from 'Helpers/Props';
|
|
||||||
import translate from 'Utilities/String/translate';
|
|
||||||
import CollectionFooterLabel from './CollectionFooterLabel';
|
|
||||||
import styles from './CollectionFooter.css';
|
|
||||||
|
|
||||||
const NO_CHANGE = 'noChange';
|
|
||||||
|
|
||||||
const monitoredOptions = [
|
|
||||||
{
|
|
||||||
key: NO_CHANGE,
|
|
||||||
get value() {
|
|
||||||
return translate('NoChange');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'monitored',
|
|
||||||
get value() {
|
|
||||||
return translate('Monitored');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'unmonitored',
|
|
||||||
get value() {
|
|
||||||
return translate('Unmonitored');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
const searchOnAddOptions = [
|
|
||||||
{
|
|
||||||
key: NO_CHANGE,
|
|
||||||
get value() {
|
|
||||||
return translate('NoChange');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'yes',
|
|
||||||
get value() {
|
|
||||||
return translate('Yes');
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'no',
|
|
||||||
get value() {
|
|
||||||
return translate('No');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
];
|
|
||||||
|
|
||||||
class CollectionFooter extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
|
|
||||||
this.state = {
|
|
||||||
monitored: NO_CHANGE,
|
|
||||||
monitor: NO_CHANGE,
|
|
||||||
qualityProfileId: NO_CHANGE,
|
|
||||||
minimumAvailability: NO_CHANGE,
|
|
||||||
rootFolderPath: NO_CHANGE,
|
|
||||||
searchOnAdd: NO_CHANGE
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
|
||||||
const {
|
|
||||||
isSaving,
|
|
||||||
saveError
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const newState = {};
|
|
||||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
|
||||||
this.setState({
|
|
||||||
monitored: NO_CHANGE,
|
|
||||||
monitor: NO_CHANGE,
|
|
||||||
qualityProfileId: NO_CHANGE,
|
|
||||||
minimumAvailability: NO_CHANGE,
|
|
||||||
rootFolderPath: NO_CHANGE,
|
|
||||||
searchOnAdd: NO_CHANGE
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!_.isEmpty(newState)) {
|
|
||||||
this.setState(newState);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onInputChange = ({ name, value }) => {
|
|
||||||
this.setState({ [name]: value });
|
|
||||||
};
|
|
||||||
|
|
||||||
onUpdateSelectedPress = () => {
|
|
||||||
const {
|
|
||||||
monitored,
|
|
||||||
monitor,
|
|
||||||
qualityProfileId,
|
|
||||||
minimumAvailability,
|
|
||||||
rootFolderPath,
|
|
||||||
searchOnAdd
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const changes = {};
|
|
||||||
|
|
||||||
if (monitored !== NO_CHANGE) {
|
|
||||||
changes.monitored = monitored === 'monitored';
|
|
||||||
}
|
|
||||||
|
|
||||||
if (monitor !== NO_CHANGE) {
|
|
||||||
changes.monitor = monitor;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (qualityProfileId !== NO_CHANGE) {
|
|
||||||
changes.qualityProfileId = qualityProfileId;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (minimumAvailability !== NO_CHANGE) {
|
|
||||||
changes.minimumAvailability = minimumAvailability;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rootFolderPath !== NO_CHANGE) {
|
|
||||||
changes.rootFolderPath = rootFolderPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (searchOnAdd !== NO_CHANGE) {
|
|
||||||
changes.searchOnAdd = searchOnAdd === 'yes';
|
|
||||||
}
|
|
||||||
|
|
||||||
this.props.onUpdateSelectedPress(changes);
|
|
||||||
};
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const {
|
|
||||||
selectedIds,
|
|
||||||
isSaving
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const {
|
|
||||||
monitored,
|
|
||||||
monitor,
|
|
||||||
qualityProfileId,
|
|
||||||
minimumAvailability,
|
|
||||||
rootFolderPath,
|
|
||||||
searchOnAdd
|
|
||||||
} = this.state;
|
|
||||||
|
|
||||||
const selectedCount = selectedIds.length;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<PageContentFooter>
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('MonitorCollection')}
|
|
||||||
isSaving={isSaving && monitored !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.SELECT}
|
|
||||||
name="monitored"
|
|
||||||
value={monitored}
|
|
||||||
values={monitoredOptions}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('MonitorMovies')}
|
|
||||||
isSaving={isSaving && monitor !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.SELECT}
|
|
||||||
name="monitor"
|
|
||||||
value={monitor}
|
|
||||||
values={monitoredOptions}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('QualityProfile')}
|
|
||||||
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
|
||||||
name="qualityProfileId"
|
|
||||||
value={qualityProfileId}
|
|
||||||
includeNoChange={true}
|
|
||||||
includeNoChangeDisabled={false}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('MinimumAvailability')}
|
|
||||||
isSaving={isSaving && minimumAvailability !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.AVAILABILITY_SELECT}
|
|
||||||
name="minimumAvailability"
|
|
||||||
value={minimumAvailability}
|
|
||||||
includeNoChange={true}
|
|
||||||
includeNoChangeDisabled={false}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('RootFolder')}
|
|
||||||
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
|
||||||
name="rootFolderPath"
|
|
||||||
value={rootFolderPath}
|
|
||||||
includeNoChange={true}
|
|
||||||
includeNoChangeDisabled={false}
|
|
||||||
selectedValueOptions={{ includeFreeSpace: false }}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.inputContainer}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('SearchMoviesOnAdd')}
|
|
||||||
isSaving={isSaving && searchOnAdd !== NO_CHANGE}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.SELECT}
|
|
||||||
name="searchOnAdd"
|
|
||||||
value={searchOnAdd}
|
|
||||||
values={searchOnAddOptions}
|
|
||||||
isDisabled={!selectedCount}
|
|
||||||
onChange={this.onInputChange}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.buttonContainer}>
|
|
||||||
<div className={styles.buttonContainerContent}>
|
|
||||||
<CollectionFooterLabel
|
|
||||||
label={translate('CountCollectionsSelected', { count: selectedCount })}
|
|
||||||
isSaving={false}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div className={styles.buttons}>
|
|
||||||
<div>
|
|
||||||
<SpinnerButton
|
|
||||||
className={styles.addSelectedButton}
|
|
||||||
kind={kinds.PRIMARY}
|
|
||||||
isSpinning={isSaving}
|
|
||||||
isDisabled={!selectedCount || isSaving}
|
|
||||||
onPress={this.onUpdateSelectedPress}
|
|
||||||
>
|
|
||||||
{translate('UpdateSelected')}
|
|
||||||
</SpinnerButton>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</PageContentFooter>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionFooter.propTypes = {
|
|
||||||
selectedIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
|
||||||
isAdding: PropTypes.bool.isRequired,
|
|
||||||
isSaving: PropTypes.bool.isRequired,
|
|
||||||
saveError: PropTypes.object,
|
|
||||||
onUpdateSelectedPress: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CollectionFooter;
|
|
||||||
317
frontend/src/Collection/CollectionFooter.tsx
Normal file
317
frontend/src/Collection/CollectionFooter.tsx
Normal file
|
|
@ -0,0 +1,317 @@
|
||||||
|
import React, { useCallback, useEffect, useState } from 'react';
|
||||||
|
import { Error } from 'App/State/AppSectionState';
|
||||||
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
|
import { EnhancedSelectInputValue } from 'Components/Form/Select/EnhancedSelectInput';
|
||||||
|
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||||
|
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||||
|
import usePrevious from 'Helpers/Hooks/usePrevious';
|
||||||
|
import { inputTypes, kinds } from 'Helpers/Props';
|
||||||
|
import { InputChanged } from 'typings/inputs';
|
||||||
|
import translate from 'Utilities/String/translate';
|
||||||
|
import CollectionFooterLabel from './CollectionFooterLabel';
|
||||||
|
import styles from './CollectionFooter.css';
|
||||||
|
|
||||||
|
interface SavePayload {
|
||||||
|
monitored?: boolean;
|
||||||
|
monitor?: string;
|
||||||
|
qualityProfileId?: number;
|
||||||
|
minimumAvailability?: string;
|
||||||
|
rootFolderPath?: string;
|
||||||
|
searchOnAdd?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CollectionFooterProps {
|
||||||
|
selectedIds: number[];
|
||||||
|
isAdding: boolean;
|
||||||
|
isSaving: boolean;
|
||||||
|
saveError: Error;
|
||||||
|
onUpdateSelectedPress(payload: object): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NO_CHANGE = 'noChange';
|
||||||
|
|
||||||
|
const monitoredOptions: EnhancedSelectInputValue<string>[] = [
|
||||||
|
{
|
||||||
|
key: NO_CHANGE,
|
||||||
|
get value() {
|
||||||
|
return translate('NoChange');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'monitored',
|
||||||
|
get value() {
|
||||||
|
return translate('Monitored');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'unmonitored',
|
||||||
|
get value() {
|
||||||
|
return translate('Unmonitored');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
const searchOnAddOptions: EnhancedSelectInputValue<string>[] = [
|
||||||
|
{
|
||||||
|
key: NO_CHANGE,
|
||||||
|
get value() {
|
||||||
|
return translate('NoChange');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'yes',
|
||||||
|
get value() {
|
||||||
|
return translate('Yes');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'no',
|
||||||
|
get value() {
|
||||||
|
return translate('No');
|
||||||
|
},
|
||||||
|
},
|
||||||
|
];
|
||||||
|
|
||||||
|
function CollectionFooter({
|
||||||
|
selectedIds,
|
||||||
|
isSaving,
|
||||||
|
saveError,
|
||||||
|
onUpdateSelectedPress,
|
||||||
|
}: CollectionFooterProps) {
|
||||||
|
const [monitored, setMonitored] = useState(NO_CHANGE);
|
||||||
|
const [monitor, setMonitor] = useState(NO_CHANGE);
|
||||||
|
const [qualityProfileId, setQualityProfileId] = useState<string | number>(
|
||||||
|
NO_CHANGE
|
||||||
|
);
|
||||||
|
const [minimumAvailability, setMinimumAvailability] = useState(NO_CHANGE);
|
||||||
|
const [rootFolderPath, setRootFolderPath] = useState(NO_CHANGE);
|
||||||
|
const [searchOnAdd, setSearchOnAdd] = useState(NO_CHANGE);
|
||||||
|
|
||||||
|
const wasSaving = usePrevious(isSaving);
|
||||||
|
|
||||||
|
const handleSavePress = useCallback(() => {
|
||||||
|
let hasChanges = false;
|
||||||
|
const payload: SavePayload = {};
|
||||||
|
|
||||||
|
if (monitored !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.monitored = monitored === 'monitored';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (monitor !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.monitor = monitor;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (qualityProfileId !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.qualityProfileId = qualityProfileId as number;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (minimumAvailability !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.minimumAvailability = minimumAvailability as string;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rootFolderPath !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.rootFolderPath = rootFolderPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (searchOnAdd !== NO_CHANGE) {
|
||||||
|
hasChanges = true;
|
||||||
|
payload.searchOnAdd = searchOnAdd === 'yes';
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasChanges) {
|
||||||
|
onUpdateSelectedPress(payload);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
monitor,
|
||||||
|
monitored,
|
||||||
|
qualityProfileId,
|
||||||
|
minimumAvailability,
|
||||||
|
rootFolderPath,
|
||||||
|
searchOnAdd,
|
||||||
|
onUpdateSelectedPress,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const handleInputChange = useCallback(({ name, value }: InputChanged) => {
|
||||||
|
switch (name) {
|
||||||
|
case 'monitored':
|
||||||
|
setMonitored(value as string);
|
||||||
|
break;
|
||||||
|
case 'monitor':
|
||||||
|
setMonitor(value as string);
|
||||||
|
break;
|
||||||
|
case 'qualityProfileId':
|
||||||
|
setQualityProfileId(value as string);
|
||||||
|
break;
|
||||||
|
case 'minimumAvailability':
|
||||||
|
setMinimumAvailability(value as string);
|
||||||
|
break;
|
||||||
|
case 'rootFolderPath':
|
||||||
|
setRootFolderPath(value as string);
|
||||||
|
break;
|
||||||
|
case 'searchOnAdd':
|
||||||
|
setSearchOnAdd(value as string);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
console.warn(`CollectionFooter Unknown Input: '${name}'`);
|
||||||
|
}
|
||||||
|
}, []);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!isSaving && wasSaving && !saveError) {
|
||||||
|
setMonitored(NO_CHANGE);
|
||||||
|
setMonitor(NO_CHANGE);
|
||||||
|
setQualityProfileId(NO_CHANGE);
|
||||||
|
setMinimumAvailability(NO_CHANGE);
|
||||||
|
setRootFolderPath(NO_CHANGE);
|
||||||
|
setSearchOnAdd(NO_CHANGE);
|
||||||
|
}
|
||||||
|
}, [
|
||||||
|
isSaving,
|
||||||
|
wasSaving,
|
||||||
|
saveError,
|
||||||
|
setMonitored,
|
||||||
|
setMonitor,
|
||||||
|
setQualityProfileId,
|
||||||
|
setMinimumAvailability,
|
||||||
|
setRootFolderPath,
|
||||||
|
setSearchOnAdd,
|
||||||
|
]);
|
||||||
|
|
||||||
|
const selectedCount = selectedIds.length;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<PageContentFooter>
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('MonitorCollection')}
|
||||||
|
isSaving={isSaving && monitored !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.SELECT}
|
||||||
|
name="monitored"
|
||||||
|
value={monitored}
|
||||||
|
values={monitoredOptions}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('MonitorMovies')}
|
||||||
|
isSaving={isSaving && monitor !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.SELECT}
|
||||||
|
name="monitor"
|
||||||
|
value={monitor}
|
||||||
|
values={monitoredOptions}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('QualityProfile')}
|
||||||
|
isSaving={isSaving && qualityProfileId !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||||
|
name="qualityProfileId"
|
||||||
|
value={qualityProfileId}
|
||||||
|
includeNoChange={true}
|
||||||
|
includeNoChangeDisabled={false}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('MinimumAvailability')}
|
||||||
|
isSaving={isSaving && minimumAvailability !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.AVAILABILITY_SELECT}
|
||||||
|
name="minimumAvailability"
|
||||||
|
value={minimumAvailability}
|
||||||
|
includeNoChange={true}
|
||||||
|
includeNoChangeDisabled={false}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('RootFolder')}
|
||||||
|
isSaving={isSaving && rootFolderPath !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||||
|
name="rootFolderPath"
|
||||||
|
value={rootFolderPath}
|
||||||
|
includeNoChange={true}
|
||||||
|
includeNoChangeDisabled={false}
|
||||||
|
selectedValueOptions={{ includeFreeSpace: false }}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('SearchMoviesOnAdd')}
|
||||||
|
isSaving={isSaving && searchOnAdd !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.SELECT}
|
||||||
|
name="searchOnAdd"
|
||||||
|
value={searchOnAdd}
|
||||||
|
values={searchOnAddOptions}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={handleInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className={styles.buttonContainer}>
|
||||||
|
<div className={styles.buttonContainerContent}>
|
||||||
|
<CollectionFooterLabel
|
||||||
|
label={translate('CountCollectionsSelected', {
|
||||||
|
count: selectedCount,
|
||||||
|
})}
|
||||||
|
isSaving={false}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div className={styles.buttons}>
|
||||||
|
<div>
|
||||||
|
<SpinnerButton
|
||||||
|
className={styles.addSelectedButton}
|
||||||
|
kind={kinds.PRIMARY}
|
||||||
|
isSpinning={isSaving}
|
||||||
|
isDisabled={!selectedCount || isSaving}
|
||||||
|
onPress={handleSavePress}
|
||||||
|
>
|
||||||
|
{translate('UpdateSelected')}
|
||||||
|
</SpinnerButton>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</PageContentFooter>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CollectionFooter;
|
||||||
|
|
@ -1,40 +0,0 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
|
||||||
import SpinnerIcon from 'Components/SpinnerIcon';
|
|
||||||
import { icons } from 'Helpers/Props';
|
|
||||||
import styles from './CollectionFooterLabel.css';
|
|
||||||
|
|
||||||
function CollectionFooterLabel(props) {
|
|
||||||
const {
|
|
||||||
className,
|
|
||||||
label,
|
|
||||||
isSaving
|
|
||||||
} = props;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<div className={className}>
|
|
||||||
{label}
|
|
||||||
|
|
||||||
{
|
|
||||||
isSaving &&
|
|
||||||
<SpinnerIcon
|
|
||||||
className={styles.savingIcon}
|
|
||||||
name={icons.SPINNER}
|
|
||||||
isSpinning={true}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
CollectionFooterLabel.propTypes = {
|
|
||||||
className: PropTypes.string.isRequired,
|
|
||||||
label: PropTypes.string.isRequired,
|
|
||||||
isSaving: PropTypes.bool.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
CollectionFooterLabel.defaultProps = {
|
|
||||||
className: styles.label
|
|
||||||
};
|
|
||||||
|
|
||||||
export default CollectionFooterLabel;
|
|
||||||
32
frontend/src/Collection/CollectionFooterLabel.tsx
Normal file
32
frontend/src/Collection/CollectionFooterLabel.tsx
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
import React from 'react';
|
||||||
|
import SpinnerIcon from 'Components/SpinnerIcon';
|
||||||
|
import { icons } from 'Helpers/Props';
|
||||||
|
import styles from './CollectionFooterLabel.css';
|
||||||
|
|
||||||
|
interface CollectionFooterLabelProps {
|
||||||
|
className?: string;
|
||||||
|
label: string;
|
||||||
|
isSaving: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
function CollectionFooterLabel({
|
||||||
|
className = styles.label,
|
||||||
|
label,
|
||||||
|
isSaving,
|
||||||
|
}: CollectionFooterLabelProps) {
|
||||||
|
return (
|
||||||
|
<div className={className}>
|
||||||
|
{label}
|
||||||
|
|
||||||
|
{isSaving ? (
|
||||||
|
<SpinnerIcon
|
||||||
|
className={styles.savingIcon}
|
||||||
|
name={icons.SPINNER}
|
||||||
|
isSpinning={true}
|
||||||
|
/>
|
||||||
|
) : null}
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export default CollectionFooterLabel;
|
||||||
|
|
@ -1,13 +1,14 @@
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import Button from 'Components/Link/Button';
|
import Button from 'Components/Link/Button';
|
||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './NoCollection.css';
|
import styles from './NoCollection.css';
|
||||||
|
|
||||||
function NoCollection(props) {
|
interface NoCollectionsProps {
|
||||||
const { totalItems } = props;
|
totalItems: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
function NoCollections({ totalItems }: NoCollectionsProps) {
|
||||||
if (totalItems > 0) {
|
if (totalItems > 0) {
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
|
|
@ -20,24 +21,16 @@ function NoCollection(props) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<div>
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>{translate('NoCollections')}</div>
|
||||||
{translate('NoCollections')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<Button
|
<Button to="/add/import" kind={kinds.PRIMARY}>
|
||||||
to="/add/import"
|
|
||||||
kind={kinds.PRIMARY}
|
|
||||||
>
|
|
||||||
{translate('ImportExistingMovies')}
|
{translate('ImportExistingMovies')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<Button
|
<Button to="/add/new" kind={kinds.PRIMARY}>
|
||||||
to="/add/new"
|
|
||||||
kind={kinds.PRIMARY}
|
|
||||||
>
|
|
||||||
{translate('AddNewMovie')}
|
{translate('AddNewMovie')}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
|
|
@ -45,8 +38,4 @@ function NoCollection(props) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
NoCollection.propTypes = {
|
export default NoCollections;
|
||||||
totalItems: PropTypes.number.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default NoCollection;
|
|
||||||
Loading…
Reference in a new issue