1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-29 18:15:37 -04:00

Compare commits

...

70 Commits

Author SHA1 Message Date
Weblate
8970b1276f Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Stevie Robinson <stevie.robinson@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2024-02-03 22:43:43 +02:00
Bogdan
e868dbf911 Fixed: Naming validation when using max token length 2024-02-03 01:38:54 +02:00
Bogdan
e38b31a220 Fix table columns order for Interactive Search 2024-02-02 23:21:19 +02:00
Bogdan
9b1dac4b57 Tests for Movie Statistics
Closes #7891
2024-02-02 22:34:14 +02:00
Bogdan
20ac0bb0e1 Avoid import loop for already imported movies
(cherry picked from commit b183743d9f0a0b15e4a9db0a9d3d2d1c238b0d9c)

Closes #9325
2024-02-02 22:34:09 +02:00
Mark McDowall
9ffa1cc2b9 Refactor select options in Manual Import
(cherry picked from commit 0685896ed8263ef6d05a933acaf584e6f4aa9f92)

Closes #9613
2024-02-02 20:45:07 +02:00
Mark McDowall
422db874f0 New: Accept ':##' on renaming tokens to allow specifying a maximum length for movie titles and release group
(cherry picked from commit 19db75b36beaa5e549d903b136dbda300f1f8562)

Closes #9713
2024-02-02 19:48:20 +02:00
Servarr
adf647f3e1 Automated API Docs update 2024-02-02 18:03:05 +02:00
Bogdan
dc81f51d40 New: Search Movies on Add for bulk manage collections
Fixes #8670
2024-02-02 17:40:08 +02:00
Mark McDowall
c9da7ee0c9 New: Use Movie Folder Format to improve unmapped folders within root folders
(cherry picked from commit 81d2b18ce1c079c2a9dc3de037c9dceea16733fd)

Closes #8065
2024-02-02 17:40:08 +02:00
Bogdan
7198aa24a6 Refactor tags in WebhookMovie 2024-02-02 17:40:08 +02:00
Weblate
35c6fef2d1 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2024-02-02 17:39:55 +02:00
Bogdan
deac2bdf5c New: Tags field for Notifiarr and Webhook 2024-02-02 04:22:35 +02:00
bakerboy448
8837473ed8 Improve Release Grabbing & Failure Logging
(cherry picked from commit d7aea82e45a7c5fec9e72b534fc4c9fb8654c519)

Closes #9714
2024-02-02 01:12:35 +02:00
Bogdan
4ac538682d Fix ImportFixture test 2024-02-02 00:59:30 +02:00
Weblate
0277b2b201 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translation: Servarr/Radarr
2024-02-02 00:05:02 +02:00
Stevie Robinson
e73015010e New: Send 'On Manual Interaction Required' notifications in more cases
(cherry picked from commit c5a724f14eec20acf565ac3a036944191b30cab0)

Closes #9722
2024-02-02 00:01:24 +02:00
Mark McDowall
f704ab1512 Improve messaging if release is in queue because all movies in release were not imported
Sync with upstream

(cherry picked from commit 2728bf79ca41bc372de515cb09e1034a8c006c2b)
2024-02-01 23:54:09 +02:00
Bogdan
2f1e077e0d Bind shortcut for pending changes confirmation only when it's shown 2024-01-31 19:42:51 +02:00
Bogdan
cd3397a7a1 Use movie specific translation for quality limits message 2024-01-31 19:42:36 +02:00
Mark McDowall
b3517c14de New: Show error message for pending queue items without movies
(cherry picked from commit 5ca868b4b2d34ba65ba3d40144ed889ccf55343d)

Closes #8320
2024-01-30 22:39:39 +02:00
Bogdan
2d05708fa9 Wrap external links tooltip in Movie Details 2024-01-30 22:22:57 +02:00
Havok Dan
2ca581f2b6 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1700 of 1700 strings)

Translation: Servarr/Radarr
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
2024-01-29 23:48:52 +02:00
Magyar
8289b8978f Translated using Weblate (Hungarian) [skip ci]
Currently translated at 74.6% (1269 of 1700 strings)

Translation: Servarr/Radarr
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
2024-01-29 23:48:52 +02:00
Oskari Lavinto
54c1f54b13 Translated using Weblate (Finnish) [skip ci]
Currently translated at 93.8% (1596 of 1700 strings)

Translation: Servarr/Radarr
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
2024-01-29 23:48:51 +02:00
fordas
918fcfd86e Translated using Weblate (Spanish) [skip ci]
Currently translated at 75.1% (1278 of 1700 strings)

Translation: Servarr/Radarr
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
2024-01-29 23:48:18 +02:00
Crocmou
f55206537c Translated using Weblate (French) [skip ci]
Currently translated at 90.4% (1538 of 1700 strings)

Translation: Servarr/Radarr
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
2024-01-29 23:47:28 +02:00
Weblate
d2d9ac8b9d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2024-01-29 23:47:26 +02:00
Stevie Robinson
ca1a40723b Add Translations to Settings Pages
(cherry picked from commit f2c31e92ceec7c6a8daffa78f30f15ab8684bef9)
2024-01-29 23:36:09 +02:00
Bogdan
bfff736cfc Translations and some cleanup for extra files and movie editor tables 2024-01-28 14:50:57 +02:00
Bogdan
c2d28dd41b Bump version to 5.3.4 2024-01-28 09:12:02 +02:00
Servarr
0e8a1ca522 Automated API Docs update 2024-01-27 21:23:24 -06:00
Qstick
1ba7bfe585 Correctly show separator for Discovery Table view 2024-01-27 21:15:28 -06:00
Qstick
0be449033f New: Trending and Popular Movies in Discovery 2024-01-27 21:15:28 -06:00
Qstick
3b1d4460ad Fixed: Only show recommendations based on library movies 2024-01-27 21:15:28 -06:00
Bogdan
4eb4128a89 Remove BOM from download clients 2024-01-28 00:01:00 +02:00
Stevie Robinson
f90cdbb112 Translate Download Clients on the backend
(cherry picked from commit 48b12f5b00429a7cd218d23f0544641b0da62a06)

Closes #9391
2024-01-27 23:49:48 +02:00
Stevie Robinson
a8dbc97921 Fixed: Validating DownloadStation output path
(cherry picked from commit 07cbd7c8d29f2e0731f0a11c685f898f7e83b0c8)

Closes #9695
2024-01-27 18:38:44 +02:00
Bogdan
f93e136386 Use string interpolation for test string
Closes #9696
2024-01-27 18:13:37 +02:00
Bogdan
a70fa0fcfe Fix improve parsing logging 2024-01-27 17:58:43 +02:00
Stevie Robinson
c8931784a7 Translate Calendar Frontend
(cherry picked from commit bf43453c040ba0474e0cd71e1c5aa3b98edf13ff)

Closes #8984
2024-01-27 17:57:38 +02:00
Weblate
f601448a65 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Crocmou <slaanesh8854@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Lars <lars.erik.heloe@gmail.com>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: diaverso <alexito_perez.95@hotmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2024-01-27 17:37:43 +02:00
bakerboy448
64125a31b6 Improve Parsing Logging 2024-01-27 17:37:17 +02:00
Weblate
2f4da90d8a Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Crocmou <slaanesh8854@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: diaverso <alexito_perez.95@hotmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2024-01-27 16:36:08 +02:00
Bogdan
20d9db2cde New: Date added for files in movie details 2024-01-27 13:18:13 +02:00
Mark McDowall
5b7c0a94fb Fixed: History retention for Newsbin
(cherry picked from commit 0ea189d03c8c5e02c00b96a4281dd9e668d6a9ae)
2024-01-27 10:16:38 +02:00
Servarr
1416f7898e Automated API Docs update 2024-01-27 10:16:21 +02:00
Bogdan
f9cd9f3204 Language comment in Manual Import
Closes #9612
2024-01-26 11:58:51 +02:00
Mark McDowall
99ab65f790 New: Add recycle bin path for deleted movies to webhook/custom script
(cherry picked from commit a71d40edba1388d67e4deefd8bfc354a7a83c6b1)

Closes #9674
2024-01-26 11:44:41 +02:00
Bogdan
82fb355930 New: External link to TMDb for Cast/Crew
Fixes #9667
Closes #9668
2024-01-24 14:03:56 +02:00
Servarr
83d437cbb3 Automated API Docs update 2024-01-24 12:28:42 +02:00
Bogdan
4beb5b328b New: Option to disable Email encryption
* New: Option to disable Email encryption

(cherry picked from commit 7be5732a3a6679120b0f01bd1eb1207194f57f5e)

* Fix possible NullRef in Email Encryption migration

(cherry picked from commit 271266b10ac51ee6dd7a7024d346b631bd5397c2)

---------

Co-authored-by: Mark McDowall <mark@mcdowall.ca>
2024-01-24 12:11:51 +02:00
Bogdan
23830f50ac Fixed: Testing for disabled Notifications 2024-01-24 12:10:57 +02:00
Weblate
b808a92cdf Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translation: Servarr/Radarr
2024-01-24 09:41:04 +02:00
Mark McDowall
3185c73659 New: Optionally remove from queue by changing category to 'Post-Import Category' when configured
(cherry picked from commit 345854d0fe9b65a561fdab12aac688782a420aa5)

Closes #9680
2024-01-24 09:37:39 +02:00
Weblate
7dc9ec03a5 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Alexander <a.burdun@gmail.com>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: wilfriedarma <wilfriedarma.collet@gmail.com>
Co-authored-by: zichichi <sollami@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translation: Servarr/Radarr
2024-01-24 08:59:10 +02:00
Servarr
33228335e3 Automated API Docs update 2024-01-24 08:58:09 +02:00
Mark McDowall
833340f8bd New: Add size to more history events
(cherry picked from commit 0d064181941fc6d149fc2f891661e059758d5428)

Closes #9672
2024-01-24 08:46:54 +02:00
Mark McDowall
0ecb1d0706 New: Add download client name to pending items waiting for a specific client
(cherry picked from commit 3cd4c67ba12cd5e8cc00d3df8929555fc0ad5918)

Closes #9676
2024-01-24 08:41:27 +02:00
Bogdan
25b77eb4a2 Update database migration version translation token
(cherry picked from commit 7d0d503a5e132cda3c03d6f7cd7b51c9c80740de)

Closes #9679
2024-01-24 08:30:52 +02:00
Stevie Robinson
b946173c05 Add Regular Expression Custom Format translation
(cherry picked from commit 9f50166fa62a71d0a23e2c2d331651792285dc0e)

Closes #9678
2024-01-24 08:28:10 +02:00
Bogdan
e5ccc32a37 Fixed: Movie status after using movie editor
Fixes #9681
2024-01-24 08:20:02 +02:00
Bogdan
3aeb52c3fd Fixed: Sorting by name in Manage Indexer and Download Client modals 2024-01-22 14:13:22 +02:00
Servarr
c717989034 Automated API Docs update 2024-01-21 16:24:34 +02:00
Bogdan
806b89abbe Fixed: Use movie file from state for status label in add search results 2024-01-21 16:17:46 +02:00
Bogdan
cc7104a814 Movie stats for Calendar 2024-01-21 16:17:46 +02:00
Bogdan
84c2d7f69d Revert "Add SizeOnDisk and HasFile to MovieResource"
This reverts commit 0ae8952b38.
2024-01-21 16:17:46 +02:00
bakerboy448
fcd187970c Improve Release Title Custom Format debugging
(cherry picked from commit ec40bc6eea1eb282cb804b8dd5461bf5ade332e9)

Closes #9653
2024-01-21 07:34:12 +02:00
Bogdan
34eb59dde4 Bump version to 5.3.3 2024-01-21 07:32:09 +02:00
Weblate
31b66c6673 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Blair Noctis <fqmxz5hyfba7ft85@neon.casa>
Co-authored-by: Dani Talens <databio@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Julian Baquero <julian-baquero@upc.edu.co>
Co-authored-by: Koch Norbert <kochnorbert@icloud.com>
Co-authored-by: MaddionMax <kovacs.tamas@ius.hu>
Co-authored-by: Magyar <kochnorbert@icloud.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: blabla <romcrack56@gmail.com>
Co-authored-by: brn <barantsenkul@gmail.com>
Co-authored-by: fordas <fordas15@gmail.com>
Co-authored-by: horvi28 <horvi28@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2024-01-21 03:50:25 +02:00
363 changed files with 7618 additions and 6063 deletions

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '5.3.2'
majorVersion: '5.3.4'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'

View File

@@ -25,7 +25,7 @@ import toggleSelected from 'Utilities/Table/toggleSelected';
import QueueFilterModal from './QueueFilterModal';
import QueueOptionsConnector from './QueueOptionsConnector';
import QueueRowConnector from './QueueRowConnector';
import RemoveQueueItemsModal from './RemoveQueueItemsModal';
import RemoveQueueItemModal from './RemoveQueueItemModal';
class Queue extends Component {
@@ -307,9 +307,16 @@ class Queue extends Component {
}
</PageContentBody>
<RemoveQueueItemsModal
<RemoveQueueItemModal
isOpen={isConfirmRemoveModalOpen}
selectedCount={selectedCount}
canChangeCategory={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
return !!(item && item.downloadClientHasPostImportCategory);
})
)}
canIgnore={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);
@@ -317,7 +324,7 @@ class Queue extends Component {
return !!(item && item.movieId);
})
)}
allPending={isConfirmRemoveModalOpen && (
pending={isConfirmRemoveModalOpen && (
selectedIds.every((id) => {
const item = items.find((i) => i.id === id);

View File

@@ -96,6 +96,7 @@ class QueueRow extends Component {
indexer,
outputPath,
downloadClient,
downloadClientHasPostImportCategory,
estimatedCompletionTime,
added,
timeleft,
@@ -373,6 +374,7 @@ class QueueRow extends Component {
<RemoveQueueItemModal
isOpen={isRemoveQueueItemModalOpen}
sourceTitle={title}
canChangeCategory={!!downloadClientHasPostImportCategory}
canIgnore={!!movie}
isPending={isPending}
onRemovePress={this.onRemoveQueueItemModalConfirmed}
@@ -402,6 +404,7 @@ QueueRow.propTypes = {
indexer: PropTypes.string,
outputPath: PropTypes.string,
downloadClient: PropTypes.string,
downloadClientHasPostImportCategory: PropTypes.bool,
estimatedCompletionTime: PropTypes.string,
added: PropTypes.string,
timeleft: PropTypes.string,

View File

@@ -1,171 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
class RemoveQueueItemModal extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
remove: true,
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
//
// Render
render() {
const {
isOpen,
sourceTitle,
canIgnore,
isPending
} = this.props;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
isOpen={isOpen}
size={sizes.MEDIUM}
onModalClose={this.onModalClose}
>
<ModalContent
onModalClose={this.onModalClose}
>
<ModalHeader>
{translate('RemoveQueueItem', { sourceTitle })}
</ModalHeader>
<ModalBody>
<div>
{translate('RemoveQueueItemConfirmation', { sourceTitle })}
</div>
{
isPending ?
null :
<FormGroup>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveFromDownloadClientHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>{translate('BlocklistRelease')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistReleaseHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody>
<ModalFooter>
<Button onPress={this.onModalClose}>
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
}
RemoveQueueItemModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
sourceTitle: PropTypes.string.isRequired,
canIgnore: PropTypes.bool.isRequired,
isPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default RemoveQueueItemModal;

View File

@@ -0,0 +1,230 @@
import React, { useCallback, useMemo, useState } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemModal.css';
interface RemovePressProps {
remove: boolean;
changeCategory: boolean;
blocklist: boolean;
skipRedownload: boolean;
}
interface RemoveQueueItemModalProps {
isOpen: boolean;
sourceTitle: string;
canChangeCategory: boolean;
canIgnore: boolean;
isPending: boolean;
selectedCount?: number;
onRemovePress(props: RemovePressProps): void;
onModalClose: () => void;
}
type RemovalMethod = 'removeFromClient' | 'changeCategory' | 'ignore';
type BlocklistMethod =
| 'doNotBlocklist'
| 'blocklistAndSearch'
| 'blocklistOnly';
function RemoveQueueItemModal(props: RemoveQueueItemModalProps) {
const {
isOpen,
sourceTitle,
canIgnore,
canChangeCategory,
isPending,
selectedCount,
onRemovePress,
onModalClose,
} = props;
const multipleSelected = selectedCount && selectedCount > 1;
const [removalMethod, setRemovalMethod] =
useState<RemovalMethod>('removeFromClient');
const [blocklistMethod, setBlocklistMethod] =
useState<BlocklistMethod>('doNotBlocklist');
const { title, message } = useMemo(() => {
if (!selectedCount) {
return {
title: translate('RemoveQueueItem', { sourceTitle }),
message: translate('RemoveQueueItemConfirmation', { sourceTitle }),
};
}
if (selectedCount === 1) {
return {
title: translate('RemoveSelectedItem'),
message: translate('RemoveSelectedItemQueueMessageText'),
};
}
return {
title: translate('RemoveSelectedItems'),
message: translate('RemoveSelectedItemsQueueMessageText', {
selectedCount,
}),
};
}, [sourceTitle, selectedCount]);
const removalMethodOptions = useMemo(() => {
return [
{
key: 'removeFromClient',
value: translate('RemoveFromDownloadClient'),
hint: multipleSelected
? translate('RemoveMultipleFromDownloadClientHint')
: translate('RemoveFromDownloadClientHint'),
},
{
key: 'changeCategory',
value: translate('ChangeCategory'),
isDisabled: !canChangeCategory,
hint: multipleSelected
? translate('ChangeCategoryMultipleHint')
: translate('ChangeCategoryHint'),
},
{
key: 'ignore',
value: multipleSelected
? translate('IgnoreDownloads')
: translate('IgnoreDownload'),
isDisabled: !canIgnore,
hint: multipleSelected
? translate('IgnoreDownloadsHint')
: translate('IgnoreDownloadHint'),
},
];
}, [canChangeCategory, canIgnore, multipleSelected]);
const blocklistMethodOptions = useMemo(() => {
return [
{
key: 'doNotBlocklist',
value: translate('DoNotBlocklist'),
hint: translate('DoNotBlocklistHint'),
},
{
key: 'blocklistAndSearch',
value: translate('BlocklistAndSearch'),
hint: multipleSelected
? translate('BlocklistAndSearchMultipleHint')
: translate('BlocklistAndSearchHint'),
},
{
key: 'blocklistOnly',
value: translate('BlocklistOnly'),
hint: multipleSelected
? translate('BlocklistMultipleOnlyHint')
: translate('BlocklistOnlyHint'),
},
];
}, [multipleSelected]);
const handleRemovalMethodChange = useCallback(
({ value }: { value: RemovalMethod }) => {
setRemovalMethod(value);
},
[setRemovalMethod]
);
const handleBlocklistMethodChange = useCallback(
({ value }: { value: BlocklistMethod }) => {
setBlocklistMethod(value);
},
[setBlocklistMethod]
);
const handleConfirmRemove = useCallback(() => {
onRemovePress({
remove: removalMethod === 'removeFromClient',
changeCategory: removalMethod === 'changeCategory',
blocklist: blocklistMethod !== 'doNotBlocklist',
skipRedownload: blocklistMethod === 'blocklistOnly',
});
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
}, [
removalMethod,
blocklistMethod,
setRemovalMethod,
setBlocklistMethod,
onRemovePress,
]);
const handleModalClose = useCallback(() => {
setRemovalMethod('removeFromClient');
setBlocklistMethod('doNotBlocklist');
onModalClose();
}, [setRemovalMethod, setBlocklistMethod, onModalClose]);
return (
<Modal isOpen={isOpen} size={sizes.MEDIUM} onModalClose={handleModalClose}>
<ModalContent onModalClose={handleModalClose}>
<ModalHeader>{title}</ModalHeader>
<ModalBody>
<div className={styles.message}>{message}</div>
{isPending ? null : (
<FormGroup>
<FormLabel>{translate('RemoveQueueItemRemovalMethod')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="removalMethod"
value={removalMethod}
values={removalMethodOptions}
isDisabled={!canChangeCategory && !canIgnore}
helpTextWarning={translate(
'RemoveQueueItemRemovalMethodHelpTextWarning'
)}
onChange={handleRemovalMethodChange}
/>
</FormGroup>
)}
<FormGroup>
<FormLabel>
{multipleSelected
? translate('BlocklistReleases')
: translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="blocklistMethod"
value={blocklistMethod}
values={blocklistMethodOptions}
helpText={translate('BlocklistReleaseHelpText')}
onChange={handleBlocklistMethodChange}
/>
</FormGroup>
</ModalBody>
<ModalFooter>
<Button onPress={handleModalClose}>{translate('Close')}</Button>
<Button kind={kinds.DANGER} onPress={handleConfirmRemove}>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
export default RemoveQueueItemModal;

View File

@@ -1,174 +0,0 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Button from 'Components/Link/Button';
import Modal from 'Components/Modal/Modal';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './RemoveQueueItemsModal.css';
class RemoveQueueItemsModal extends Component {
//
// Lifecycle
constructor(props, context) {
super(props, context);
this.state = {
remove: true,
blocklist: false,
skipRedownload: false
};
}
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipRedownload: false
});
};
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
//
// Render
render() {
const {
isOpen,
selectedCount,
canIgnore,
allPending
} = this.props;
const { remove, blocklist, skipRedownload } = this.state;
return (
<Modal
isOpen={isOpen}
size={sizes.MEDIUM}
onModalClose={this.onModalClose}
>
<ModalContent
onModalClose={this.onModalClose}
>
<ModalHeader>
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
</ModalHeader>
<ModalBody>
<div className={styles.message}>
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', { selectedCount }) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
allPending ?
null :
<FormGroup>
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="remove"
value={remove}
helpTextWarning={translate('RemoveHelpTextWarning')}
isDisabled={!canIgnore}
onChange={this.onRemoveChange}
/>
</FormGroup>
}
<FormGroup>
<FormLabel>
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="blocklist"
value={blocklist}
helpText={translate('BlocklistReleaseHelpText')}
onChange={this.onBlocklistChange}
/>
</FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody>
<ModalFooter>
<Button onPress={this.onModalClose}>
{translate('Close')}
</Button>
<Button
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}
}
RemoveQueueItemsModal.propTypes = {
isOpen: PropTypes.bool.isRequired,
selectedCount: PropTypes.number.isRequired,
canIgnore: PropTypes.bool.isRequired,
allPending: PropTypes.bool.isRequired,
onRemovePress: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired
};
export default RemoveQueueItemsModal;

View File

@@ -3,10 +3,13 @@ import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions';
import { clearMovieFiles, fetchMovieFiles } from 'Store/Actions/movieFileActions';
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import selectUniqueIds from 'Utilities/Object/selectUniqueIds';
import parseUrl from 'Utilities/String/parseUrl';
import AddNewMovie from './AddNewMovie';
@@ -35,7 +38,9 @@ const mapDispatchToProps = {
fetchRootFolders,
fetchImportExclusions,
fetchQueueDetails,
clearQueueDetails
clearQueueDetails,
fetchMovieFiles,
clearMovieFiles
};
class AddNewMovieConnector extends Component {
@@ -55,6 +60,20 @@ class AddNewMovieConnector extends Component {
this.props.fetchQueueDetails();
}
componentDidUpdate(prevProps) {
const {
items
} = this.props;
if (hasDifferentItems(prevProps.items, items)) {
const movieIds = selectUniqueIds(items, 'internalId');
if (movieIds.length) {
this.props.fetchMovieFiles({ movieId: movieIds });
}
}
}
componentWillUnmount() {
if (this._movieLookupTimeout) {
clearTimeout(this._movieLookupTimeout);
@@ -62,6 +81,7 @@ class AddNewMovieConnector extends Component {
this.props.clearAddMovie();
this.props.clearQueueDetails();
this.props.clearMovieFiles();
}
//
@@ -107,12 +127,15 @@ class AddNewMovieConnector extends Component {
AddNewMovieConnector.propTypes = {
term: PropTypes.string,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
lookupMovie: PropTypes.func.isRequired,
clearAddMovie: PropTypes.func.isRequired,
fetchRootFolders: PropTypes.func.isRequired,
fetchImportExclusions: PropTypes.func.isRequired,
fetchQueueDetails: PropTypes.func.isRequired,
clearQueueDetails: PropTypes.func.isRequired
clearQueueDetails: PropTypes.func.isRequired,
fetchMovieFiles: PropTypes.func.isRequired,
clearMovieFiles: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);

View File

@@ -75,7 +75,6 @@ class AddNewMovieSearchResult extends Component {
colorImpairedMode,
id,
monitored,
hasFile,
isAvailable,
movieFile,
queueItem,
@@ -88,6 +87,8 @@ class AddNewMovieSearchResult extends Component {
isNewAddMovieModalOpen
} = this.state;
const hasMovieFile = !!movieFile;
const linkProps = isExistingMovie ? { to: `/movie/${titleSlug}` } : { onPress: this.onPress };
const posterWidth = 167;
const posterHeight = 250;
@@ -126,7 +127,7 @@ class AddNewMovieSearchResult extends Component {
movieId={existingMovieId}
movieFile={movieFile}
monitored={monitored}
hasFile={hasFile}
hasFile={hasMovieFile}
status={status}
width={posterWidth}
detailedProgressBar={true}
@@ -270,7 +271,7 @@ class AddNewMovieSearchResult extends Component {
{
isExistingMovie && isSmallScreen &&
<MovieStatusLabel
hasMovieFiles={hasFile}
hasMovieFiles={hasMovieFile}
monitored={monitored}
isAvailable={isAvailable}
queueItem={queueItem}
@@ -322,7 +323,6 @@ AddNewMovieSearchResult.propTypes = {
isSmallScreen: PropTypes.bool.isRequired,
id: PropTypes.number,
monitored: PropTypes.bool.isRequired,
hasFile: PropTypes.bool.isRequired,
isAvailable: PropTypes.bool.isRequired,
movieFile: PropTypes.object,
queueItem: PropTypes.object,

View File

@@ -11,10 +11,12 @@ function createMapStateToProps() {
createExclusionMovieSelector(),
createDimensionsSelector(),
(state) => state.queue.details.items,
(state) => state.movieFiles.items,
(state, { internalId }) => internalId,
(state) => state.settings.ui.item.movieRuntimeFormat,
(isExistingMovie, isExclusionMovie, dimensions, queueItems, internalId, movieRuntimeFormat) => {
(isExistingMovie, isExclusionMovie, dimensions, queueItems, movieFiles, internalId, movieRuntimeFormat) => {
const queueItem = queueItems.find((item) => internalId > 0 && item.movieId === internalId);
const movieFile = movieFiles.find((item) => internalId > 0 && item.movieId === internalId);
return {
existingMovieId: internalId,
@@ -22,6 +24,7 @@ function createMapStateToProps() {
isExclusionMovie,
isSmallScreen: dimensions.isSmallScreen,
queueItem,
movieFile,
movieRuntimeFormat
};
}

View File

@@ -10,6 +10,7 @@ import styles from './ImportMovieRow.css';
function ImportMovieRow(props) {
const {
id,
relativePath,
monitor,
qualityProfileId,
minimumAvailability,
@@ -31,7 +32,7 @@ function ImportMovieRow(props) {
/>
<VirtualTableRowCell className={styles.folder}>
{id}
{relativePath}
</VirtualTableRowCell>
<VirtualTableRowCell className={styles.movie}>
@@ -73,6 +74,7 @@ function ImportMovieRow(props) {
ImportMovieRow.propTypes = {
id: PropTypes.string.isRequired,
relativePath: PropTypes.string.isRequired,
monitor: PropTypes.string.isRequired,
qualityProfileId: PropTypes.number.isRequired,
minimumAvailability: PropTypes.string.isRequired,

View File

@@ -30,7 +30,7 @@ class ImportMovieTable extends Component {
unmappedFolders.forEach((unmappedFolder) => {
const id = unmappedFolder.name;
onMovieLookup(id, unmappedFolder.path);
onMovieLookup(id, unmappedFolder.path, unmappedFolder.relativePath);
onSetImportMovieValue({
id,

View File

@@ -25,10 +25,11 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
onMovieLookup(name, path) {
onMovieLookup(name, path, relativePath) {
dispatch(queueLookupMovie({
name,
path,
relativePath,
term: name
}));
},

View File

@@ -33,9 +33,7 @@ class Calendar extends Component {
{
!isFetching && !!error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadTheCalendar')}
</Alert>
<Alert kind={kinds.DANGER}>{translate('CalendarLoadError')}</Alert>
}
{

View File

@@ -104,7 +104,7 @@ class CalendarPage extends Component {
<PageToolbar>
<PageToolbarSection>
<PageToolbarButton
label={translate('iCalLink')}
label={translate('ICalLink')}
iconName={icons.CALENDAR}
onPress={this.onGetCalendarLinkPress}
/>
@@ -112,7 +112,7 @@ class CalendarPage extends Component {
<PageToolbarSeparator />
<PageToolbarButton
label={translate('RSSSync')}
label={translate('RssSync')}
iconName={icons.RSS}
isSpinning={isRssSyncExecuting}
onPress={onRssSyncPress}
@@ -180,7 +180,7 @@ class CalendarPage extends Component {
{
!movieError && movieIsPopulated && !hasMovie &&
<NoMovie />
<NoMovie totalItems={0} />
}
{

View File

@@ -126,7 +126,7 @@ class CalendarHeader extends Component {
isDisabled={view === calendarViews.AGENDA}
onPress={onTodayPress}
>
Today
{translate('Today')}
</Button>
</div>

View File

@@ -135,7 +135,7 @@ class CalendarOptionsModalContent extends Component {
type={inputTypes.CHECK}
name="showCutoffUnmetIcon"
value={showCutoffUnmetIcon}
helpText={translate('ShowCutoffUnmetIconHelpText')}
helpText={translate('IconForCutoffUnmetHelpText')}
onChange={this.onOptionInputChange}
/>
</FormGroup>
@@ -177,7 +177,7 @@ class CalendarOptionsModalContent extends Component {
values={weekColumnOptions}
value={calendarWeekColumnHeader}
onChange={this.onGlobalInputChange}
helpText={translate('SettingsWeekColumnHeaderHelpText')}
helpText={translate('WeekColumnHeaderHelpText')}
/>
</FormGroup>

View File

@@ -109,7 +109,7 @@ class CalendarLinkModalContent extends Component {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{translate('RadarrCalendarFeed')}
{translate('CalendarFeed')}
</ModalHeader>
<ModalBody>
@@ -121,19 +121,19 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.CHECK}
name="unmonitored"
value={unmonitored}
helpText={translate('UnmonitoredHelpText')}
helpText={translate('ICalIncludeUnmonitoredMoviesHelpText')}
onChange={this.onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('ShowAsAllDayEvents')}</FormLabel>
<FormLabel>{translate('ICalShowAsAllDayEvents')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="asAllDay"
value={asAllDay}
helpText={translate('AsAllDayHelpText')}
helpText={translate('ICalShowAsAllDayEventsHelpText')}
onChange={this.onInputChange}
/>
</FormGroup>
@@ -145,7 +145,7 @@ class CalendarLinkModalContent extends Component {
type={inputTypes.TAG}
name="tags"
value={tags}
helpText={translate('TagsHelpText')}
helpText={translate('ICalTagsMoviesHelpText')}
onChange={this.onInputChange}
/>
</FormGroup>
@@ -160,7 +160,7 @@ class CalendarLinkModalContent extends Component {
name="iCalHttpUrl"
value={iCalHttpUrl}
readOnly={true}
helpText={translate('ICalHttpUrlHelpText')}
helpText={translate('ICalFeedHelpText')}
buttons={[
<ClipboardButton
key="copy"

View File

@@ -14,6 +14,50 @@ import styles from './CollectionFooter.css';
const NO_CHANGE = 'noChange';
const monitoredOptions = [
{
key: NO_CHANGE,
get value() {
return translate('NoChange');
},
disabled: true
},
{
key: 'monitored',
get value() {
return translate('Monitored');
}
},
{
key: 'unmonitored',
get value() {
return translate('Unmonitored');
}
}
];
const searchOnAddOptions = [
{
key: NO_CHANGE,
get value() {
return translate('NoChange');
},
disabled: true
},
{
key: 'yes',
get value() {
return translate('Yes');
}
},
{
key: 'no',
get value() {
return translate('No');
}
}
];
class CollectionFooter extends Component {
//
@@ -23,12 +67,12 @@ class CollectionFooter extends Component {
super(props, context);
this.state = {
monitor: NO_CHANGE,
monitored: NO_CHANGE,
monitor: NO_CHANGE,
qualityProfileId: NO_CHANGE,
minimumAvailability: NO_CHANGE,
rootFolderPath: NO_CHANGE,
destinationRootFolder: null
searchOnAdd: NO_CHANGE
};
}
@@ -44,8 +88,9 @@ class CollectionFooter extends Component {
monitored: NO_CHANGE,
monitor: NO_CHANGE,
qualityProfileId: NO_CHANGE,
minimumAvailability: NO_CHANGE,
rootFolderPath: NO_CHANGE,
minimumAvailability: NO_CHANGE
searchOnAdd: NO_CHANGE
});
}
@@ -63,11 +108,12 @@ class CollectionFooter extends Component {
onUpdateSelectedPress = () => {
const {
monitor,
monitored,
monitor,
qualityProfileId,
minimumAvailability,
rootFolderPath
rootFolderPath,
searchOnAdd
} = this.state;
const changes = {};
@@ -92,6 +138,10 @@ class CollectionFooter extends Component {
changes.rootFolderPath = rootFolderPath;
}
if (searchOnAdd !== NO_CHANGE) {
changes.searchOnAdd = searchOnAdd === 'yes';
}
this.props.onUpdateSelectedPress(changes);
};
@@ -109,15 +159,10 @@ class CollectionFooter extends Component {
monitor,
qualityProfileId,
minimumAvailability,
rootFolderPath
rootFolderPath,
searchOnAdd
} = this.state;
const monitoredOptions = [
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
{ key: 'monitored', value: translate('Monitored') },
{ key: 'unmonitored', value: translate('Unmonitored') }
];
const selectedCount = selectedIds.length;
return (
@@ -125,7 +170,7 @@ class CollectionFooter extends Component {
<div className={styles.inputContainer}>
<CollectionFooterLabel
label={translate('MonitorCollection')}
isSaving={isSaving}
isSaving={isSaving && monitored !== NO_CHANGE}
/>
<SelectInput
@@ -140,7 +185,7 @@ class CollectionFooter extends Component {
<div className={styles.inputContainer}>
<CollectionFooterLabel
label={translate('MonitorMovies')}
isSaving={isSaving}
isSaving={isSaving && monitor !== NO_CHANGE}
/>
<SelectInput
@@ -198,10 +243,25 @@ class CollectionFooter extends Component {
/>
</div>
<div className={styles.inputContainer}>
<CollectionFooterLabel
label={translate('SearchMoviesOnAdd')}
isSaving={isSaving && searchOnAdd !== NO_CHANGE}
/>
<SelectInput
name="searchOnAdd"
value={searchOnAdd}
values={searchOnAddOptions}
isDisabled={!selectedCount}
onChange={this.onInputChange}
/>
</div>
<div className={styles.buttonContainer}>
<div className={styles.buttonContainerContent}>
<CollectionFooterLabel
label={translate('CollectionsSelectedInterp', [selectedCount])}
label={translate('CountCollectionsSelected', { count: selectedCount })}
isSaving={false}
/>

View File

@@ -267,6 +267,7 @@ FormInputGroup.propTypes = {
name: PropTypes.string.isRequired,
value: PropTypes.any,
values: PropTypes.arrayOf(PropTypes.any),
isDisabled: PropTypes.bool,
type: PropTypes.string.isRequired,
kind: PropTypes.oneOf(kinds.all),
min: PropTypes.number,

View File

@@ -19,7 +19,7 @@ function ImportListList({ lists, importListList }) {
return (
<Label
key={list.id}
kind={kinds.INFO}
kind={kinds.SUCCESS}
size={sizes.MEDIUM}
>
{list.name}

View File

@@ -101,7 +101,7 @@ const links = [
to: '/settings/downloadclients'
},
{
title: () => translate('Lists'),
title: () => translate('ImportLists'),
to: '/settings/importlists'
},
{
@@ -121,7 +121,7 @@ const links = [
to: '/settings/general'
},
{
title: () => translate('UI'),
title: () => translate('Ui'),
to: '/settings/ui'
}
]

View File

@@ -329,10 +329,7 @@ class DiscoverMovie extends Component {
null
}
{
(view === 'posters' || view === 'overview') &&
<PageToolbarSeparator />
}
<PageToolbarSeparator />
<DiscoverMovieViewMenu
view={view}

View File

@@ -97,6 +97,8 @@ class DiscoverMovieOverview extends Component {
isExisting,
isExcluded,
isRecommendation,
isPopular,
isTrending,
isSelected,
overviewOptions,
...otherProps
@@ -214,6 +216,26 @@ class DiscoverMovieOverview extends Component {
null
}
{
isPopular ?
<Label
kind={kinds.INFO}
>
{translate('Popular')}
</Label> :
null
}
{
isTrending ?
<Label
kind={kinds.INFO}
>
{translate('Trending')}
</Label> :
null
}
<ImportListListConnector
lists={lists}
/>
@@ -283,6 +305,8 @@ DiscoverMovieOverview.propTypes = {
isExisting: PropTypes.bool.isRequired,
isExcluded: PropTypes.bool.isRequired,
isRecommendation: PropTypes.bool.isRequired,
isPopular: PropTypes.bool.isRequired,
isTrending: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
lists: PropTypes.arrayOf(PropTypes.number).isRequired,
onSelectedChange: PropTypes.func.isRequired

View File

@@ -57,10 +57,12 @@
flex: 0 0 115px;
}
.isTrending,
.isPopular,
.isRecommendation {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
flex: 0 0 50px;
flex: 0 0 30px;
}
.actions {

View File

@@ -7,7 +7,9 @@ interface CssExports {
'digitalRelease': string;
'genres': string;
'inCinemas': string;
'isPopular': string;
'isRecommendation': string;
'isTrending': string;
'lists': string;
'originalLanguage': string;
'physicalRelease': string;

View File

@@ -103,6 +103,40 @@ class DiscoverMovieHeader extends Component {
);
}
if (name === 'isTrending') {
return (
<VirtualTableHeaderCell
key={name}
className={styles[name]}
name={name}
isSortable={true}
{...otherProps}
>
<Icon
name={icons.TRENDING}
size={12}
/>
</VirtualTableHeaderCell>
);
}
if (name === 'isPopular') {
return (
<VirtualTableHeaderCell
key={name}
className={styles[name]}
name={name}
isSortable={true}
{...otherProps}
>
<Icon
name={icons.POPULAR}
size={12}
/>
</VirtualTableHeaderCell>
);
}
return (
<VirtualTableHeaderCell
key={name}

View File

@@ -76,10 +76,12 @@
flex: 1 0 110px;
}
.isTrending,
.isPopular,
.isRecommendation {
composes: cell;
flex: 0 0 50px;
flex: 0 0 30px;
}
.actions {
@@ -95,6 +97,11 @@
margin-top: 0;
}
.statusIcon {
width: 20px !important;
text-align: center;
}
.externalLinks {
margin-right: 0.5em;
}

View File

@@ -12,7 +12,9 @@ interface CssExports {
'externalLinks': string;
'genres': string;
'inCinemas': string;
'isPopular': string;
'isRecommendation': string;
'isTrending': string;
'lists': string;
'originalLanguage': string;
'physicalRelease': string;
@@ -21,6 +23,7 @@ interface CssExports {
'runtime': string;
'sortTitle': string;
'status': string;
'statusIcon': string;
'studio': string;
}
export const cssExports: CssExports;

View File

@@ -82,6 +82,8 @@ class DiscoverMovieRow extends Component {
isExisting,
isExcluded,
isRecommendation,
isTrending,
isPopular,
isSelected,
lists,
onSelectedChange
@@ -305,6 +307,7 @@ class DiscoverMovieRow extends Component {
{
isRecommendation ?
<Icon
className={styles.statusIcon}
name={icons.RECOMMENDED}
size={12}
title={translate('MovieIsRecommend')}
@@ -315,6 +318,46 @@ class DiscoverMovieRow extends Component {
);
}
if (name === 'isTrending') {
return (
<VirtualTableRowCell
key={name}
className={styles[name]}
>
{
isTrending ?
<Icon
className={styles.statusIcon}
name={icons.TRENDING}
size={12}
title={translate('MovieIsTrending')}
/> :
null
}
</VirtualTableRowCell>
);
}
if (name === 'isPopular') {
return (
<VirtualTableRowCell
key={name}
className={styles[name]}
>
{
isPopular ?
<Icon
className={styles.statusIcon}
name={icons.POPULAR}
size={12}
title={translate('MovieIsPopular')}
/> :
null
}
</VirtualTableRowCell>
);
}
if (name === 'actions') {
return (
<VirtualTableRowCell
@@ -404,6 +447,8 @@ DiscoverMovieRow.propTypes = {
isExcluded: PropTypes.bool.isRequired,
isSelected: PropTypes.bool,
isRecommendation: PropTypes.bool.isRequired,
isPopular: PropTypes.bool.isRequired,
isTrending: PropTypes.bool.isRequired,
lists: PropTypes.arrayOf(PropTypes.number).isRequired,
onSelectedChange: PropTypes.func.isRequired
};

View File

@@ -23,6 +23,7 @@ import {
import {
faArrowCircleLeft as fasArrowCircleLeft,
faArrowCircleRight as fasArrowCircleRight,
faArrowTrendUp as fasArrowTrendUp,
faAsterisk as fasAsterisk,
faBackward as fasBackward,
faBan as fasBan,
@@ -233,6 +234,7 @@ export const TAGS = fasTags;
export const TBA = fasQuestionCircle;
export const TEST = fasVial;
export const TRANSLATE = fasLanguage;
export const TRENDING = fasArrowTrendUp;
export const UNGROUP = farObjectUngroup;
export const UNKNOWN = fasQuestion;
export const UNMONITORED = farBookmark;

View File

@@ -242,25 +242,6 @@ function InteractiveImportModalContent(
const [interactiveImportErrorMessage, setInteractiveImportErrorMessage] =
useState<string | null>(null);
const [selectState, setSelectState] = useSelectState();
const [bulkSelectOptions, setBulkSelectOptions] = useState([
{
key: 'select',
value: translate('SelectDropdown'),
disabled: true,
},
{
key: 'quality',
value: translate('SelectQuality'),
},
{
key: 'releaseGroup',
value: translate('SelectReleaseGroup'),
},
{
key: 'language',
value: translate('SelectLanguage'),
},
]);
const { allSelected, allUnselected, selectedState } = selectState;
const previousIsDeleting = usePrevious(isDeleting);
const dispatch = useDispatch();
@@ -283,19 +264,39 @@ function InteractiveImportModalContent(
return getSelectedIds(selectedState);
}, [selectedState]);
const bulkSelectOptions = useMemo(() => {
const options = [
{
key: 'select',
value: translate('SelectDropdown'),
disabled: true,
},
{
key: 'quality',
value: translate('SelectQuality'),
},
{
key: 'releaseGroup',
value: translate('SelectReleaseGroup'),
},
{
key: 'language',
value: translate('SelectLanguage'),
},
];
if (allowMovieChange) {
options.splice(1, 0, {
key: 'movie',
value: translate('SelectMovie'),
});
}
return options;
}, [allowMovieChange]);
useEffect(
() => {
if (allowMovieChange) {
const newBulkSelectOptions = [...bulkSelectOptions];
newBulkSelectOptions.splice(1, 0, {
key: 'movie',
value: translate('SelectMovie'),
});
setBulkSelectOptions(newBulkSelectOptions);
}
if (initialSortKey) {
const sortProps: { sortKey: string; sortDirection?: string } = {
sortKey: initialSortKey,

View File

@@ -88,13 +88,6 @@ const columns = [
isSortable: true,
isVisible: true
},
{
name: 'releaseWeight',
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
},
{
name: 'rejections',
label: React.createElement(Icon, {
@@ -104,6 +97,13 @@ const columns = [
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
},
{
name: 'releaseWeight',
label: React.createElement(Icon, { name: icons.DOWNLOAD }),
isSortable: true,
fixedSortDirection: sortDirections.ASCENDING,
isVisible: true
}
];

View File

@@ -1,8 +1,14 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import Link from 'Components/Link/Link';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, sizes } from 'Helpers/Props';
import MovieHeadshot from 'Movie/MovieHeadshot';
import EditImportListModalConnector from 'Settings/ImportLists/ImportLists/EditImportListModalConnector';
import translate from 'Utilities/String/translate';
import styles from '../MovieCreditPoster.css';
class MovieCastPoster extends Component {
@@ -52,6 +58,7 @@ class MovieCastPoster extends Component {
render() {
const {
tmdbId,
personName,
character,
images,
@@ -83,15 +90,35 @@ class MovieCastPoster extends Component {
style={contentStyle}
>
<div className={styles.posterContainer}>
<div className={styles.controls}>
<div className={styles.toggleMonitoredContainer}>
<MonitorToggleButton
className={styles.action}
className={styles.monitorToggleButton}
monitored={monitored}
size={20}
onPress={importListId > 0 ? this.onEditImportListPress : this.onAddImportListPress}
/>
</div>
<Label className={styles.controls}>
<span className={styles.externalLinks}>
<Popover
anchor={<Icon name={icons.EXTERNAL_LINK} size={12} />}
title={translate('Links')}
body={
<Link to={`https://www.themoviedb.org/person/${tmdbId}`}>
<Label
className={styles.externalLinkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
{translate('TMDb')}
</Label>
</Link>
}
/>
</span>
</Label>
<div
style={elementStyle}
>

View File

@@ -1,8 +1,14 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import Link from 'Components/Link/Link';
import MonitorToggleButton from 'Components/MonitorToggleButton';
import Popover from 'Components/Tooltip/Popover';
import { icons, kinds, sizes } from 'Helpers/Props';
import MovieHeadshot from 'Movie/MovieHeadshot';
import EditImportListModalConnector from 'Settings/ImportLists/ImportLists/EditImportListModalConnector';
import translate from 'Utilities/String/translate';
import styles from '../MovieCreditPoster.css';
class MovieCrewPoster extends Component {
@@ -52,6 +58,7 @@ class MovieCrewPoster extends Component {
render() {
const {
tmdbId,
personName,
job,
images,
@@ -83,15 +90,35 @@ class MovieCrewPoster extends Component {
style={contentStyle}
>
<div className={styles.posterContainer}>
<div className={styles.controls}>
<div className={styles.toggleMonitoredContainer}>
<MonitorToggleButton
className={styles.action}
className={styles.monitorToggleButton}
monitored={monitored}
size={20}
onPress={importListId > 0 ? this.onEditImportListPress : this.onAddImportListPress}
/>
</div>
<Label className={styles.controls}>
<span className={styles.externalLinks}>
<Popover
anchor={<Icon name={icons.EXTERNAL_LINK} size={12} />}
title={translate('Links')}
body={
<Link to={`https://www.themoviedb.org/person/${tmdbId}`}>
<Label
className={styles.externalLinkLabel}
kind={kinds.INFO}
size={sizes.LARGE}
>
{translate('TMDb')}
</Label>
</Link>
}
/>
</span>
</Label>
<div
style={elementStyle}
>

View File

@@ -1,13 +1,17 @@
$hoverScale: 1.05;
.content {
border-radius: '5px';
transition: all 200ms ease-in;
&:hover {
z-index: 2;
box-shadow: 0 0 12px var(--black);
transition: all 200ms ease-in;
.controls {
opacity: 0.9;
transition: opacity 200ms linear 150ms;
}
}
}
@@ -44,13 +48,13 @@ $hoverScale: 1.05;
font-size: $smallFontSize;
}
.controls {
.toggleMonitoredContainer {
position: absolute;
top: 10px;
z-index: 3;
}
.action {
.monitorToggleButton {
composes: toggleButton from '~Components/MonitorToggleButton.css';
width: 25px;
@@ -61,8 +65,39 @@ $hoverScale: 1.05;
}
}
.controls {
position: absolute;
bottom: 10px;
left: 10px;
z-index: 3;
border-radius: 4px;
background-color: #707070;
color: var(--white);
font-size: $smallFontSize;
opacity: 0;
transition: opacity 0;
}
.action {
composes: button from '~Components/Link/IconButton.css';
&:hover {
color: var(--iconButtonHoverLightColor);
}
}
@media only screen and (max-width: $breakpointSmall) {
.container {
padding: 5px;
}
}
.externalLinks {
margin: 0 2px;
}
.externalLinkLabel {
composes: label from '~Components/Label.css';
cursor: pointer;
}

View File

@@ -5,10 +5,14 @@ interface CssExports {
'container': string;
'content': string;
'controls': string;
'externalLinkLabel': string;
'externalLinks': string;
'monitorToggleButton': string;
'overlayTitle': string;
'poster': string;
'posterContainer': string;
'title': string;
'toggleMonitoredContainer': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -3,6 +3,7 @@
}
.link {
display: inline-block;
white-space: nowrap;
}

View File

@@ -235,7 +235,7 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
/>
<PageToolbarButton
label={translate('RSSSync')}
label={translate('RssSync')}
iconName={icons.RSS}
isSpinning={isRssSyncExecuting}
isDisabled={hasNoMovie}

View File

@@ -45,7 +45,8 @@
width: 165px;
}
.releaseGroup {
.releaseGroup,
.dateAdded {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 120px;

View File

@@ -6,6 +6,7 @@ interface CssExports {
'audio': string;
'audioLanguages': string;
'customFormatScore': string;
'dateAdded': string;
'download': string;
'formats': string;
'language': string;

View File

@@ -2,6 +2,7 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import IconButton from 'Components/Link/IconButton';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import Tooltip from 'Components/Tooltip/Tooltip';
@@ -82,6 +83,7 @@ class MovieFileEditorRow extends Component {
customFormats,
customFormatScore,
languages,
dateAdded,
columns
} = this.props;
@@ -287,6 +289,16 @@ class MovieFileEditorRow extends Component {
);
}
if (name === 'dateAdded') {
return (
<RelativeDateCellConnector
key={name}
className={styles.dateAdded}
date={dateAdded}
/>
);
}
if (name === 'actions') {
return (
<TableRowCell key={name} className={styles.actions}>
@@ -354,6 +366,7 @@ MovieFileEditorRow.propTypes = {
qualityCutoffNotMet: PropTypes.bool.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
mediaInfo: PropTypes.object,
dateAdded: PropTypes.string,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
onDeletePress: PropTypes.func.isRequired
};

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 translate from 'Utilities/String/translate';
import MovieFileEditorRow from './MovieFileEditorRow';
import styles from './MovieFileEditorTableContent.css';
@@ -22,7 +23,7 @@ class MovieFileEditorTableContent extends Component {
{
!items.length &&
<div className={styles.blankpad}>
No movie files to manage.
{translate('NoMovieFilesToManage')}
</div>
}

View File

@@ -23,9 +23,7 @@ function createMapStateToProps() {
) => {
const languages = languageProfiles.items;
const qualities = getQualities(qualityProfiles.schema.items);
const filesForMovie = movieFiles.items.filter((obj) => {
return obj.movieId === movieId;
});
const filesForMovie = movieFiles.items.filter((file) => file.movieId === movieId);
return {
items: filesForMovie,
@@ -42,11 +40,11 @@ function createMapStateToProps() {
function createMapDispatchToProps(dispatch, props) {
return {
dispatchFetchQualityProfileSchema(name, path) {
dispatchFetchQualityProfileSchema() {
dispatch(fetchQualityProfileSchema());
},
dispatchFetchLanguages(name, path) {
dispatchFetchLanguages() {
dispatch(fetchLanguages());
},

View File

@@ -46,7 +46,7 @@ class ExtraFileTableContent extends Component {
{
!items.length &&
<div className={styles.blankpad}>
No extra files to manage.
{translate('NoExtraFilesToManage')}
</div>
}

View File

@@ -14,9 +14,7 @@ function createMapStateToProps() {
movieId,
extraFiles
) => {
const filesForMovie = extraFiles.items.filter((obj) => {
return obj.movieId === movieId;
});
const filesForMovie = extraFiles.items.filter((file) => file.movieId === movieId);
return {
items: filesForMovie,
@@ -26,11 +24,6 @@ function createMapStateToProps() {
);
}
function createMapDispatchToProps(dispatch, props) {
return {
};
}
class ExtraFileTableContentConnector extends Component {
//
@@ -53,4 +46,4 @@ ExtraFileTableContentConnector.propTypes = {
movieId: PropTypes.number.isRequired
};
export default connect(createMapStateToProps, createMapDispatchToProps)(ExtraFileTableContentConnector);
export default connect(createMapStateToProps, null)(ExtraFileTableContentConnector);

View File

@@ -6,11 +6,12 @@ import PageContentBody from 'Components/Page/PageContentBody';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import ParseToolbarButton from 'Parse/ParseToolbarButton';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
import CustomFormatsConnector from './CustomFormats/CustomFormatsConnector';
function CustomFormatSettingsPage() {
return (
<PageContent title="Custom Format Settings">
<PageContent title={translate('CustomFormatsSettings')}>
<SettingsToolbarConnector
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore

View File

@@ -61,7 +61,7 @@ class CustomFormats extends Component {
return (
<FieldSet legend={translate('CustomFormats')}>
<PageSectionContent
errorMessage={translate('UnableToLoadCustomFormats')}
errorMessage={translate('CustomFormatsLoadError')}
{...otherProps}c={true}
>
<div className={styles.customFormats}>

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Card from 'Components/Card';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
@@ -112,9 +113,9 @@ class EditCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewCustomFormatPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddCustomFormatError')}
</Alert>
}
{

View File

@@ -43,7 +43,7 @@ class ExportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
{translate('CustomFormatsLoadError')}
</Alert>
}

View File

@@ -97,7 +97,7 @@ class ImportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
{translate('CustomFormatsLoadError')}
</Alert>
}

View File

@@ -89,7 +89,9 @@ class ImportCustomFormatModalContentConnector extends Component {
const selectedImplementation = _.find(this.props.specificationSchema, { implementation: spec.implementation });
if (!selectedImplementation) {
throw new Error(translate('CustomFormatUnknownCondition', [spec.implementation]));
throw new Error(translate('CustomFormatUnknownCondition', {
implementation: spec.implementation
}));
}
this.props.selectCustomFormatSpecificationSchema({ implementation: spec.implementation });
@@ -109,7 +111,10 @@ class ImportCustomFormatModalContentConnector extends Component {
for (const [key, value] of Object.entries(fields)) {
const field = _.find(schema.fields, { name: key });
if (!field) {
throw new Error(translate('CustomFormatUnknownConditionOption', [key, schema.implementationName]));
throw new Error(translate('CustomFormatUnknownConditionOption', {
key,
implementation: schema.implementationName
}));
}
this.props.setCustomFormatSpecificationFieldValue({ name: key, value });

View File

@@ -43,7 +43,7 @@ class AddSpecificationModalContent extends Component {
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewConditionPleaseTryAgain')}
{translate('AddConditionError')}
</div>
}
@@ -53,10 +53,10 @@ class AddSpecificationModalContent extends Component {
<Alert kind={kinds.INFO}>
<div>
{translate('RadarrSupportsCustomConditionsAgainstTheReleasePropertiesBelow')}
{translate('SupportedCustomConditions')}
</div>
<div>
{translate('VisitGithubCustomFormatsAphrodite')}
{translate('VisitTheWikiForMoreDetails')}
<Link to="https://wiki.servarr.com/radarr/settings#custom-formats-2">{translate('Wiki')}</Link>
</div>
</Alert>

View File

@@ -7,8 +7,8 @@ import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import ProviderFieldFormGroup from 'Components/Form/ProviderFieldFormGroup';
import Button from 'Components/Link/Button';
import Link from 'Components/Link/Link';
import SpinnerErrorButton from 'Components/Link/SpinnerErrorButton';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
@@ -49,15 +49,16 @@ function EditSpecificationModalContent(props) {
{...otherProps}
>
{
fields && fields.some((x) => x.label === 'Regular Expression') &&
fields && fields.some((x) => x.label === translate('CustomFormatsSpecificationRegularExpression')) &&
<Alert kind={kinds.INFO}>
<div>
<div dangerouslySetInnerHTML={{ __html: translate('ThisConditionMatchesUsingRegularExpressions', ['<code>\\^$.|?*+()[{</code>', '<code>\\</code>']) }} />
{translate('MoreDetails')} <Link to="https://www.regular-expressions.info/tutorial.html">{translate('LinkHere')}</Link>
<InlineMarkdown data={translate('ConditionUsingRegularExpressions')} />
</div>
<div>
{translate('RegularExpressionsCanBeTested')}
<Link to="http://regexstorm.net/tester">{translate('LinkHere')}</Link>
<InlineMarkdown data={translate('RegularExpressionsTutorialLink')} />
</div>
<div>
<InlineMarkdown data={translate('RegularExpressionsCanBeTested')} />
</div>
</Alert>
}
@@ -99,7 +100,7 @@ function EditSpecificationModalContent(props) {
type={inputTypes.CHECK}
name="negate"
{...negate}
helpText={translate('NegateHelpText', [implementationName])}
helpText={translate('NegateHelpText', { implementationName })}
onChange={onInputChange}
/>
</FormGroup>
@@ -113,7 +114,7 @@ function EditSpecificationModalContent(props) {
type={inputTypes.CHECK}
name="required"
{...required}
helpText={translate('RequiredHelpText', [implementationName, implementationName])}
helpText={translate('RequiredHelpText', { implementationName })}
onChange={onInputChange}
/>
</FormGroup>

View File

@@ -43,9 +43,9 @@ class AddDownloadClientModalContent extends Component {
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddDownloadClientError')}
</Alert>
}
{
@@ -54,10 +54,10 @@ class AddDownloadClientModalContent extends Component {
<Alert kind={kinds.INFO}>
<div>
{translate('RadarrSupportsAnyDownloadClient')}
{translate('SupportedDownloadClients')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualDownloadClients')}
{translate('SupportedDownloadClientsMoreInfo')}
</div>
</Alert>

View File

@@ -69,9 +69,9 @@ class EditDownloadClientModalContent extends Component {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewDownloadClientPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddDownloadClientError')}
</Alert>
}
{
@@ -147,7 +147,7 @@ class EditDownloadClientModalContent extends Component {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('DownloadClientTagHelpText')}
helpText={translate('DownloadClientMovieTagHelpText')}
{...tags}
onChange={onInputChange}
/>
@@ -184,7 +184,6 @@ class EditDownloadClientModalContent extends Component {
</FormGroup>
}
</FieldSet>
</Form>
}
</ModalBody>

View File

@@ -30,7 +30,7 @@ function DownloadClientOptions(props) {
{
!isFetching && error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadDownloadClientOptions')}
{translate('DownloadClientOptionsLoadError')}
</Alert>
}
@@ -38,6 +38,7 @@ function DownloadClientOptions(props) {
hasSettings && !isFetching && !error && advancedSettings &&
<div>
<FieldSet legend={translate('CompletedDownloadHandling')}>
<Form>
<FormGroup
advancedSettings={advancedSettings}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -52,9 +53,9 @@ function EditRemotePathMappingModalContent(props) {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewRemotePathMappingPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddRemotePathMappingError')}
</Alert>
}
{
@@ -66,7 +67,7 @@ function EditRemotePathMappingModalContent(props) {
<FormInputGroup
type={inputTypes.SELECT}
name="host"
helpText={translate('SettingsRemotePathMappingHostHelpText')}
helpText={translate('RemotePathMappingHostHelpText')}
{...host}
values={downloadClientHosts}
onChange={onInputChange}
@@ -74,24 +75,24 @@ function EditRemotePathMappingModalContent(props) {
</FormGroup>
<FormGroup>
<FormLabel>{translate('SettingsRemotePathMappingRemotePath')}</FormLabel>
<FormLabel>{translate('RemotePath')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="remotePath"
helpText={translate('SettingsRemotePathMappingRemotePathHelpText')}
helpText={translate('RemotePathMappingRemotePathHelpText')}
{...remotePath}
onChange={onInputChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('SettingsRemotePathMappingLocalPath')}</FormLabel>
<FormLabel>{translate('LocalPath')}</FormLabel>
<FormInputGroup
type={inputTypes.PATH}
name="localPath"
helpText={translate('SettingsRemotePathMappingLocalPathHelpText')}
helpText={translate('RemotePathMappingLocalPathHelpText')}
{...localPath}
onChange={onInputChange}
/>

View File

@@ -49,12 +49,12 @@ class RemotePathMappings extends Component {
return (
<FieldSet legend={translate('RemotePathMappings')}>
<PageSectionContent
errorMessage={translate('UnableToLoadRemotePathMappings')}
errorMessage={translate('RemotePathMappingsLoadError')}
{...otherProps}
>
<Alert kind={kinds.INFO}>
<InlineMarkdown data={translate('RemotePathMappingsInfo', { app: 'Radarr', wikiLink: 'https://wiki.servarr.com/radarr/settings#remote-path-mappings' })} />
<InlineMarkdown data={translate('RemotePathMappingsInfo', { wikiLink: 'https://wiki.servarr.com/radarr/settings#remote-path-mappings' })} />
</Alert>
<div className={styles.remotePathMappingsHeader}>

View File

@@ -22,6 +22,7 @@ const requiresRestartKeys = [
'bindAddress',
'port',
'urlBase',
'instanceName',
'enableSsl',
'sslPort',
'sslCertPath',
@@ -125,7 +126,7 @@ class GeneralSettings extends Component {
{
!isFetching && error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadGeneralSettings')}
{translate('GeneralSettingsLoadError')}
</Alert>
}
@@ -186,10 +187,8 @@ class GeneralSettings extends Component {
isOpen={this.state.isRestartRequiredModalOpen}
kind={kinds.DANGER}
title={translate('RestartRadarr')}
message={
`Radarr requires a restart to apply changes, do you want to restart now? ${isWindowsService ? 'Depending which user is running the Radarr service you may need to restart Radarr as admin once before the service will start automatically.' : ''}`
}
cancelLabel={translate('IllRestartLater')}
message={`${translate('RestartRequiredToApplyChanges')} ${isWindowsService ? translate('RestartRequiredWindowsService') : ''}`}
cancelLabel={translate('RestartLater')}
confirmLabel={translate('RestartNow')}
onConfirm={this.onConfirmRestart}
onCancel={this.onCloseRestartRequiredModalOpen}

View File

@@ -63,7 +63,7 @@ function HostSettings(props) {
</FormGroup>
<FormGroup>
<FormLabel>{translate('URLBase')}</FormLabel>
<FormLabel>{translate('UrlBase')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
@@ -111,7 +111,7 @@ function HostSettings(props) {
isAdvanced={true}
size={sizes.MEDIUM}
>
<FormLabel>{translate('EnableSSL')}</FormLabel>
<FormLabel>{translate('EnableSsl')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
@@ -128,7 +128,7 @@ function HostSettings(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('SSLPort')}</FormLabel>
<FormLabel>{translate('SslPort')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
@@ -149,12 +149,12 @@ function HostSettings(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('SSLCertPath')}</FormLabel>
<FormLabel>{translate('SslCertPath')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="sslCertPath"
helpText={translate('SSLCertPathHelpText')}
helpText={translate('SslCertPathHelpText')}
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
onChange={onInputChange}
{...sslCertPath}
@@ -169,12 +169,12 @@ function HostSettings(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('SSLCertPassword')}</FormLabel>
<FormLabel>{translate('SslCertPassword')}</FormLabel>
<FormInputGroup
type={inputTypes.PASSWORD}
name="sslCertPassword"
helpText={translate('SSLCertPasswordHelpText')}
helpText={translate('SslCertPasswordHelpText')}
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
onChange={onInputChange}
{...sslCertPassword}
@@ -184,18 +184,19 @@ function HostSettings(props) {
}
{
isWindows && mode !== 'service' &&
isWindows && mode !== 'service' ?
<FormGroup size={sizes.MEDIUM}>
<FormLabel>{translate('OpenBrowserOnStart')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="launchBrowser"
helpText={translate('LaunchBrowserHelpText')}
helpText={translate('OpenBrowserOnStartHelpText')}
onChange={onInputChange}
{...launchBrowser}
/>
</FormGroup>
</FormGroup> :
null
}
</FieldSet>

View File

@@ -25,9 +25,18 @@ function ProxySettings(props) {
} = settings;
const proxyTypeOptions = [
{ key: 'http', value: translate('HttpHttps') },
{ key: 'socks4', value: translate('Socks4') },
{ key: 'socks5', value: translate('Socks5') }
{
key: 'http',
value: translate('HttpHttps')
},
{
key: 'socks4',
value: translate('Socks4')
},
{
key: 'socks5',
value: translate('Socks5')
}
];
return (

View File

@@ -70,7 +70,8 @@ function UpdateSettings(props) {
</FormGroup>
{
!isWindows &&
isWindows ?
null :
<div>
<FormGroup
advancedSettings={advancedSettings}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -39,7 +40,7 @@ function EditImportListExclusionModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id ? translate('EditListExclusion') : translate('AddListExclusion')}
{id ? translate('EditImportListExclusion') : translate('AddImportListExclusion')}
</ModalHeader>
<ModalBody className={styles.body}>
@@ -50,9 +51,9 @@ function EditImportListExclusionModalContent(props) {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewListExclusionPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddImportListExclusionError')}
</Alert>
}
{

View File

@@ -45,14 +45,14 @@ class ImportListExclusions extends Component {
} = this.props;
return (
<FieldSet legend={translate('ListExclusions')}>
<FieldSet legend={translate('ImportListExclusions')}>
<PageSectionContent
errorMessage={translate('UnableToLoadListExclusions')}
errorMessage={translate('ImportListExclusionsLoadError')}
{...otherProps}
>
<div className={styles.importListExclusionsHeader}>
<div className={styles.tmdbId}>
TMDb Id
{translate('TMDBId')}
</div>
<div className={styles.title}>
{translate('Title')}

View File

@@ -70,7 +70,7 @@ class ImportListSettings extends Component {
} = this.state;
return (
<PageContent title={translate('ListSettings')}>
<PageContent title={translate('ImportListSettings')}>
<SettingsToolbarConnector
isSaving={isSaving}
hasPendingChanges={hasPendingChanges}

View File

@@ -37,42 +37,46 @@ class AddImportListModalContent extends Component {
<ModalBody>
{
isSchemaFetching &&
<LoadingIndicator />
isSchemaFetching ?
<LoadingIndicator /> :
null
}
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewListPleaseTryAgain')}
</div>
!isSchemaFetching && !!schemaError ?
<Alert kind={kinds.DANGER}>
{translate('AddListError')}
</Alert> :
null
}
{
isSchemaPopulated && !schemaError &&
isSchemaPopulated && !schemaError ?
<div>
<Alert kind={kinds.INFO}>
<div>
{translate('RadarrSupportsAnyRSSMovieListsAsWellAsTheOneStatedBelow')}
{translate('SupportedListsMovie')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualImportListsClinkOnTheInfoButtons')}
{translate('SupportedListsMoreInfo')}
</div>
</Alert>
{
Object.keys(listGroups).map((key) => {
return (
<FieldSet legend={`${titleCase(key)} List`} key={key}>
<FieldSet key={key} legend={translate('TypeOfList', {
typeOfList: titleCase(key)
})}
>
<div className={styles.importLists}>
{
listGroups[key].map((importList) => {
listGroups[key].map((list) => {
return (
<AddImportListItem
key={importList.implementation}
implementation={importList.implementation}
{...importList}
key={list.implementation}
implementation={list.implementation}
{...list}
onImportListSelect={onImportListSelect}
/>
);
@@ -83,7 +87,8 @@ class AddImportListModalContent extends Component {
);
})
}
</div>
</div> :
null
}
</ModalBody>
<ModalFooter>

View File

@@ -67,10 +67,11 @@ function EditImportListModalContent(props) {
}
{
!isFetching && (!!error || !!rootFolderError) &&
<div>
{translate('UnableToAddANewListPleaseTryAgain')}
</div>
!isFetching && (!!error || !!rootFolderError) ?
<Alert kind={kinds.DANGER}>
{translate('AddListError')}
</Alert> :
null
}
{
@@ -92,7 +93,9 @@ function EditImportListModalContent(props) {
kind={kinds.INFO}
className={styles.message}
>
{translate('ListWillRefreshEveryInterp', [formatShortTimeSpan(minRefreshInterval.value)])}
{translate('ListWillRefreshEveryInterval', {
refreshInterval: formatShortTimeSpan(minRefreshInterval.value)
})}
</Alert>
<FormGroup>
@@ -112,7 +115,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enabled"
helpText={translate('EnabledHelpText')}
helpText={translate('ListEnabledHelpText')}
{...enabled}
onChange={onInputChange}
/>
@@ -124,7 +127,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enableAuto"
helpText={translate('EnableAutoHelpText')}
helpText={translate('EnableAutomaticAddMovieHelpText')}
{...enableAuto}
onChange={onInputChange}
/>
@@ -136,7 +139,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.MOVIE_MONITORED_SELECT}
name="monitor"
helpText={translate('ShouldMonitorHelpText')}
helpText={translate('ListMonitorMovieHelpText')}
{...monitor}
onChange={onInputChange}
/>
@@ -148,7 +151,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="searchOnAdd"
helpText={translate('SearchOnAddHelpText')}
helpText={translate('ListSearchOnAddMovieHelpText')}
{...searchOnAdd}
onChange={onInputChange}
/>
@@ -170,6 +173,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId"
helpText={translate('ListQualityProfileHelpText')}
{...qualityProfileId}
onChange={onInputChange}
/>
@@ -181,6 +185,7 @@ function EditImportListModalContent(props) {
<FormInputGroup
type={inputTypes.ROOT_FOLDER_SELECT}
name="rootFolderPath"
helpText={translate('ListRootFolderHelpText')}
{...rootFolderPath}
includeMissingValue={true}
onChange={onInputChange}

View File

@@ -89,7 +89,7 @@ class ImportList extends Component {
{
enableAuto &&
<Label kind={kinds.SUCCESS}>
{translate('Auto')}
{translate('AutomaticAdd')}
</Label>
}
</div>

View File

@@ -59,9 +59,9 @@ class ImportLists extends Component {
} = this.state;
return (
<FieldSet legend={translate('Lists')}>
<FieldSet legend={translate('ImportLists')} >
<PageSectionContent
errorMessage={translate('UnableToLoadLists')}
errorMessage={translate('ImportListsLoadError')}
{...otherProps}
>
<div className={styles.importLists}>

View File

@@ -43,9 +43,9 @@ class AddIndexerModalContent extends Component {
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewIndexerPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddIndexerError')}
</Alert>
}
{
@@ -54,10 +54,10 @@ class AddIndexerModalContent extends Component {
<Alert kind={kinds.INFO}>
<div>
{translate('RadarrSupportsAnyIndexer')}
{translate('SupportedIndexers')}
</div>
<div>
{translate('ForMoreInformationOnTheIndividualIndexers')}
{translate('SupportedIndexersMoreInfo')}
</div>
</Alert>

View File

@@ -67,7 +67,7 @@ function EditIndexerModalContent(props) {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewIndexerPleaseTryAgain')}
{translate('AddIndexerError')}
</div>
}
@@ -86,13 +86,13 @@ function EditIndexerModalContent(props) {
</FormGroup>
<FormGroup>
<FormLabel>{translate('EnableRSS')}</FormLabel>
<FormLabel>{translate('EnableRss')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="enableRss"
helpText={supportsRss.value ? translate('RSSHelpText') : undefined}
helpTextWarning={supportsRss.value ? undefined : translate('RSSIsNotSupportedWithThisIndexer')}
helpText={supportsRss.value ? translate('EnableRssHelpText') : undefined}
helpTextWarning={supportsRss.value ? undefined : translate('RssIsNotSupportedWithThisIndexer')}
isDisabled={!supportsRss.value}
{...enableRss}
onChange={onInputChange}
@@ -106,7 +106,7 @@ function EditIndexerModalContent(props) {
type={inputTypes.CHECK}
name="enableAutomaticSearch"
helpText={supportsSearch.value ? translate('EnableAutomaticSearchHelpText') : undefined}
helpTextWarning={supportsSearch.value ? undefined : translate('EnableAutomaticSearchHelpTextWarning')}
helpTextWarning={supportsSearch.value ? undefined : translate('SearchIsNotSupportedWithThisIndexer')}
isDisabled={!supportsSearch.value}
{...enableAutomaticSearch}
onChange={onInputChange}
@@ -120,7 +120,7 @@ function EditIndexerModalContent(props) {
type={inputTypes.CHECK}
name="enableInteractiveSearch"
helpText={supportsSearch.value ? translate('EnableInteractiveSearchHelpText') : undefined}
helpTextWarning={supportsSearch.value ? undefined : translate('EnableInteractiveSearchHelpTextWarning')}
helpTextWarning={supportsSearch.value ? undefined : translate('SearchIsNotSupportedWithThisIndexer')}
isDisabled={!supportsSearch.value}
{...enableInteractiveSearch}
onChange={onInputChange}
@@ -182,7 +182,7 @@ function EditIndexerModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('IndexerTagHelpText')}
helpText={translate('IndexerTagMovieHelpText')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -101,7 +101,7 @@ class Indexer extends Component {
{
supportsRss && enableRss &&
<Label kind={kinds.SUCCESS}>
{translate('RSS')}
{translate('Rss')}
</Label>
}

View File

@@ -70,7 +70,7 @@ class Indexers extends Component {
return (
<FieldSet legend={translate('Indexers')}>
<PageSectionContent
errorMessage={translate('UnableToLoadIndexers')}
errorMessage={translate('IndexersLoadError')}
{...otherProps}
>
<div className={styles.indexers}>

View File

@@ -127,7 +127,7 @@ function ManageIndexersEditModalContent(
<ModalBody>
<FormGroup>
<FormLabel>{translate('EnableRSS')}</FormLabel>
<FormLabel>{translate('EnableRss')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}

View File

@@ -50,7 +50,7 @@ const COLUMNS = [
},
{
name: 'enableRss',
label: () => translate('EnableRSS'),
label: () => translate('EnableRss'),
isSortable: true,
isVisible: true,
},

View File

@@ -31,7 +31,7 @@ function IndexerOptions(props) {
{
!isFetching && error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
{translate('IndexerOptionsLoadError')}
</Alert>
}
@@ -110,7 +110,7 @@ function IndexerOptions(props) {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('RSSSyncInterval')}</FormLabel>
<FormLabel>{translate('RssSyncInterval')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
@@ -118,8 +118,8 @@ function IndexerOptions(props) {
min={0}
max={120}
unit="minutes"
helpText={translate('RssSyncHelpText')}
helpTextWarning={translate('RSSSyncIntervalHelpTextWarning')}
helpText={translate('RssSyncIntervalHelpText')}
helpTextWarning={translate('RssSyncIntervalHelpTextWarning')}
helpLink="https://wiki.servarr.com/radarr/faq#how-does-radarr-work"
onChange={onInputChange}
{...settings.rssSyncInterval}

View File

@@ -119,7 +119,7 @@ class MediaManagement extends Component {
!isFetching && error ?
<FieldSet legend={translate('NamingSettings')}>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMediaManagementSettings')}
{translate('MediaManagementSettingsLoadError')}
</Alert>
</FieldSet> : null
}
@@ -204,7 +204,7 @@ class MediaManagement extends Component {
type={inputTypes.NUMBER}
unit='MB'
name="minimumFreeSpaceWhenImporting"
helpText={translate('MinimumFreeSpaceWhenImportingHelpText')}
helpText={translate('MinimumFreeSpaceHelpText')}
onChange={onInputChange}
{...settings.minimumFreeSpaceWhenImporting}
/>
@@ -220,7 +220,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="copyUsingHardlinks"
helpText={translate('CopyUsingHardlinksHelpText')}
helpText={translate('CopyUsingHardlinksMovieHelpText')}
helpTextWarning={translate('CopyUsingHardlinksHelpTextWarning')}
onChange={onInputChange}
{...settings.copyUsingHardlinks}
@@ -237,7 +237,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="useScriptImport"
helpText={translate('UseScriptImportHelpText')}
helpText={translate('ImportUsingScriptHelpText')}
onChange={onInputChange}
{...settings.useScriptImport}
/>
@@ -255,7 +255,7 @@ class MediaManagement extends Component {
type={inputTypes.PATH}
includeFiles={true}
name="scriptImportPath"
helpText={translate('ScriptImportPathHelpText')}
helpText={translate('ImportScriptPathHelpText')}
onChange={onInputChange}
{...settings.scriptImportPath}
/>
@@ -268,7 +268,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="importExtraFiles"
helpText={translate('ImportExtraFilesHelpText')}
helpText={translate('ImportExtraFilesMovieHelpText')}
onChange={onInputChange}
{...settings.importExtraFiles}
/>
@@ -286,8 +286,8 @@ class MediaManagement extends Component {
type={inputTypes.TEXT}
name="extraFileExtensions"
helpTexts={[
translate('ExtraFileExtensionsHelpTexts1'),
translate('ExtraFileExtensionsHelpTexts2')
translate('ExtraFileExtensionsHelpText'),
translate('ExtraFileExtensionsHelpTextsExamples')
]}
onChange={onInputChange}
{...settings.extraFileExtensions}
@@ -323,8 +323,8 @@ class MediaManagement extends Component {
type={inputTypes.SELECT}
name="downloadPropersAndRepacks"
helpTexts={[
translate('DownloadPropersAndRepacksHelpText1'),
translate('DownloadPropersAndRepacksHelpText2')
translate('DownloadPropersAndRepacksHelpText'),
translate('DownloadPropersAndRepacksHelpTextCustomFormat')
]}
helpTextWarning={
settings.downloadPropersAndRepacks.value === 'doNotPrefer' ?
@@ -347,7 +347,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.CHECK}
name="enableMediaInfo"
helpText={translate('EnableMediaInfoHelpText')}
helpText={translate('AnalyseVideoFilesHelpText')}
onChange={onInputChange}
{...settings.enableMediaInfo}
/>
@@ -362,7 +362,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.SELECT}
name="rescanAfterRefresh"
helpText={translate('RescanAfterRefreshHelpText')}
helpText={translate('RescanAfterRefreshMovieHelpText')}
helpTextWarning={translate('RescanAfterRefreshHelpTextWarning')}
values={rescanAfterRefreshOptions}
onChange={onInputChange}
@@ -379,7 +379,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.SELECT}
name="fileDate"
helpText={translate('FileDateHelpText')}
helpText={translate('ChangeFileDateHelpText')}
values={fileDateOptions}
onChange={onInputChange}
{...settings.fileDate}
@@ -395,7 +395,7 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.PATH}
name="recycleBin"
helpText={translate('RecycleBinHelpText')}
helpText={translate('RecyclingBinHelpText')}
onChange={onInputChange}
{...settings.recycleBin}
/>
@@ -410,8 +410,8 @@ class MediaManagement extends Component {
<FormInputGroup
type={inputTypes.NUMBER}
name="recycleBinCleanupDays"
helpText={translate('RecycleBinCleanupDaysHelpText')}
helpTextWarning={translate('RecycleBinCleanupDaysHelpTextWarning')}
helpText={translate('RecyclingBinCleanupHelpText')}
helpTextWarning={translate('RecyclingBinCleanupHelpTextWarning')}
min={0}
onChange={onInputChange}
{...settings.recycleBinCleanupDays}
@@ -461,13 +461,13 @@ class MediaManagement extends Component {
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ChmodGroup')}</FormLabel>
<FormLabel>{translate('ChownGroup')}</FormLabel>
<FormInputGroup
type={inputTypes.TEXT}
name="chownGroup"
helpText={translate('ChmodGroupHelpText')}
helpTextWarning={translate('ChmodGroupHelpTextWarning')}
helpText={translate('ChownGroupHelpText')}
helpTextWarning={translate('ChownGroupHelpTextWarning')}
values={fileDateOptions}
onChange={onInputChange}
{...settings.chownGroup}

View File

@@ -110,7 +110,7 @@ class Naming extends Component {
if (examplesPopulated) {
if (examples.movieExample) {
standardMovieFormatHelpTexts.push(`Movie: ${examples.movieExample}`);
standardMovieFormatHelpTexts.push(`${translate('Movie')}: ${examples.movieExample}`);
} else {
standardMovieFormatErrors.push({ get message() {
return translate('MovieInvalidFormat');
@@ -118,7 +118,7 @@ class Naming extends Component {
}
if (examples.movieFolderExample) {
movieFolderFormatHelpTexts.push(`Example: ${examples.movieFolderExample}`);
movieFolderFormatHelpTexts.push(`${translate('Example')}: ${examples.movieFolderExample}`);
} else {
movieFolderFormatErrors.push({ get message() {
return translate('InvalidFormat');
@@ -136,7 +136,7 @@ class Naming extends Component {
{
!isFetching && error &&
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadNamingSettings')}
{translate('NamingSettingsLoadError')}
</Alert>
}
@@ -214,7 +214,7 @@ class Naming extends Component {
buttons={<FormInputButton onPress={this.onMovieFolderNamingModalOpenClick}>?</FormInputButton>}
onChange={onInputChange}
{...settings.movieFolderFormat}
helpTexts={['Used when adding a new movie or moving movies via the editor', ...movieFolderFormatHelpTexts]}
helpTexts={[translate('MovieFolderFormatHelpText'), ...movieFolderFormatHelpTexts]}
errors={[...movieFolderFormatErrors, ...settings.movieFolderFormat.errors]}
/>
</FormGroup>

View File

@@ -5,6 +5,7 @@ import SelectInput from 'Components/Form/SelectInput';
import TextInput from 'Components/Form/TextInput';
import Icon from 'Components/Icon';
import Button from 'Components/Link/Button';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import Modal from 'Components/Modal/Modal';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
@@ -16,10 +17,30 @@ import NamingOption from './NamingOption';
import styles from './NamingModal.css';
const separatorOptions = [
{ key: ' ', value: 'Space ( )' },
{ key: '.', value: 'Period (.)' },
{ key: '_', value: 'Underscore (_)' },
{ key: '-', value: 'Dash (-)' }
{
key: ' ',
get value() {
return `${translate('Space')} ( )`;
}
},
{
key: '.',
get value() {
return `${translate('Period')} (.)`;
}
},
{
key: '_',
get value() {
return `${translate('Underscore')} (_)`;
}
},
{
key: '-',
get value() {
return `${translate('Dash')} (-)`;
}
}
];
const caseOptions = [
@@ -32,13 +53,13 @@ const caseOptions = [
{
key: 'lower',
get value() {
return translate('LowerCase');
return translate('Lowercase');
}
},
{
key: 'upper',
get value() {
return translate('UpperCase');
return translate('Uppercase');
}
}
];
@@ -336,10 +357,7 @@ class NamingModal extends Component {
<div className={styles.footNote}>
<Icon className={styles.icon} name={icons.FOOTNOTE} />
<div>
MediaInfo Full/AudioLanguages/SubtitleLanguages support a <code>:EN+DE</code> suffix allowing you to filter the languages included in the filename. Use <code>-DE</code> to exclude specific languages.
Appending <code>+</code> (eg <code>:EN+</code>) will output <code>[EN]</code>/<code>[EN+--]</code>/<code>[--]</code> depending on excluded languages. For example <code>{'{'}MediaInfo Full:EN+DE{'}'}</code>.
</div>
<InlineMarkdown data={translate('MediaInfoFootNote')} />
</div>
</FieldSet>

View File

@@ -36,7 +36,7 @@ function EditMetadataModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
Edit {name.value} Metadata
{translate('EditMetadata', { metadataType: name.value })}
</ModalHeader>
<ModalBody>
@@ -47,7 +47,7 @@ function EditMetadataModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enable"
helpText={translate('EnableHelpText')}
helpText={translate('EnableMetadataHelpText')}
{...enable}
onChange={onInputChange}
/>

View File

@@ -15,7 +15,7 @@ function Metadatas(props) {
return (
<FieldSet legend={translate('Metadata')}>
<PageSectionContent
errorMessage={translate('UnableToLoadMetadata')}
errorMessage={translate('MetadataLoadError')}
{...otherProps}
>
<div className={styles.metadatas}>

View File

@@ -1,11 +1,13 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ModalBody from 'Components/Modal/ModalBody';
import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AddNotificationItem from './AddNotificationItem';
import styles from './AddNotificationModalContent.css';
@@ -39,9 +41,9 @@ class AddNotificationModalContent extends Component {
{
!isSchemaFetching && !!schemaError &&
<div>
{translate('UnableToAddANewNotificationPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddNotificationError')}
</Alert>
}
{

View File

@@ -59,9 +59,9 @@ function EditNotificationModalContent(props) {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewNotificationPleaseTryAgain')}
</div>
<Alert kind={kinds.DANGER}>
{translate('AddNotificationError')}
</Alert>
}
{
@@ -99,7 +99,7 @@ function EditNotificationModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('TagsHelpText')}
helpText={translate('NotificationsTagsMovieHelpText')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -55,7 +55,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onGrab"
helpText={translate('OnGrabHelpText')}
helpText={translate('OnGrab')}
isDisabled={!supportsOnGrab.value}
{...onGrab}
onChange={onInputChange}
@@ -66,7 +66,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onDownload"
helpText={translate('OnDownloadHelpText')}
helpText={translate('OnImport')}
isDisabled={!supportsOnDownload.value}
{...onDownload}
onChange={onInputChange}
@@ -79,7 +79,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onUpgrade"
helpText={translate('OnUpgradeHelpText')}
helpText={translate('OnUpgrade')}
isDisabled={!supportsOnUpgrade.value}
{...onUpgrade}
onChange={onInputChange}
@@ -91,7 +91,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onRename"
helpText={translate('OnRenameHelpText')}
helpText={translate('OnRename')}
isDisabled={!supportsOnRename.value}
{...onRename}
onChange={onInputChange}
@@ -102,7 +102,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onMovieAdded"
helpText={translate('OnMovieAddedHelpText')}
helpText={translate('OnMovieAdded')}
isDisabled={!supportsOnMovieAdded.value}
{...onMovieAdded}
onChange={onInputChange}
@@ -113,7 +113,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onMovieDelete"
helpText={translate('OnMovieDeleteHelpText')}
helpText={translate('OnMovieDelete')}
isDisabled={!supportsOnMovieDelete.value}
{...onMovieDelete}
onChange={onInputChange}
@@ -124,7 +124,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onMovieFileDelete"
helpText={translate('OnMovieFileDeleteHelpText')}
helpText={translate('OnMovieFileDelete')}
isDisabled={!supportsOnMovieFileDelete.value}
{...onMovieFileDelete}
onChange={onInputChange}
@@ -137,7 +137,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onMovieFileDeleteForUpgrade"
helpText={translate('OnMovieFileDeleteForUpgradeHelpText')}
helpText={translate('OnMovieFileDeleteForUpgrade')}
isDisabled={!supportsOnMovieFileDeleteForUpgrade.value}
{...onMovieFileDeleteForUpgrade}
onChange={onInputChange}
@@ -149,7 +149,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onHealthIssue"
helpText={translate('OnHealthIssueHelpText')}
helpText={translate('OnHealthIssue')}
isDisabled={!supportsOnHealthIssue.value}
{...onHealthIssue}
onChange={onInputChange}
@@ -160,7 +160,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onHealthRestored"
helpText={translate('OnHealthRestoredHelpText')}
helpText={translate('OnHealthRestored')}
isDisabled={!supportsOnHealthRestored.value}
{...onHealthRestored}
onChange={onInputChange}
@@ -173,7 +173,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="includeHealthWarnings"
helpText={translate('IncludeHealthWarningsHelpText')}
helpText={translate('IncludeHealthWarnings')}
isDisabled={!supportsOnHealthIssue.value}
{...includeHealthWarnings}
onChange={onInputChange}
@@ -185,7 +185,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onApplicationUpdate"
helpText={translate('OnApplicationUpdateHelpText')}
helpText={translate('OnApplicationUpdate')}
isDisabled={!supportsOnApplicationUpdate.value}
{...onApplicationUpdate}
onChange={onInputChange}
@@ -196,7 +196,7 @@ function NotificationEventItems(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="onManualInteractionRequired"
helpText={translate('OnManualInteractionRequiredHelpText')}
helpText={translate('OnManualInteractionRequired')}
isDisabled={!supportsOnManualInteractionRequired.value}
{...onManualInteractionRequired}
onChange={onInputChange}

View File

@@ -62,7 +62,7 @@ class Notifications extends Component {
return (
<FieldSet legend={translate('Connections')}>
<PageSectionContent
errorMessage={translate('UnableToLoadNotifications')}
errorMessage={translate('NotificationsLoadError')}
{...otherProps}
>
<div className={styles.notifications}>

View File

@@ -15,12 +15,17 @@ function PendingChangesModal(props) {
isOpen,
onConfirm,
onCancel,
bindShortcut
bindShortcut,
unbindShortcut
} = props;
useEffect(() => {
bindShortcut('enter', onConfirm);
}, [bindShortcut, onConfirm]);
if (isOpen) {
bindShortcut('enter', onConfirm);
return () => unbindShortcut('enter', onConfirm);
}
}, [bindShortcut, unbindShortcut, isOpen, onConfirm]);
return (
<Modal
@@ -61,7 +66,8 @@ PendingChangesModal.propTypes = {
kind: PropTypes.oneOf(kinds.all),
onConfirm: PropTypes.func.isRequired,
onCancel: PropTypes.func.isRequired,
bindShortcut: PropTypes.func.isRequired
bindShortcut: PropTypes.func.isRequired,
unbindShortcut: PropTypes.func.isRequired
};
PendingChangesModal.defaultProps = {

View File

@@ -17,15 +17,15 @@ function getDelay(enabled, delay) {
}
if (!delay) {
return 'No Delay';
return translate('NoDelay');
}
if (delay === 1) {
return '1 Minute';
return translate('OneMinute');
}
// TODO: use better units of time than just minutes
return `${delay} Minutes`;
return translate('DelayMinutes', { delay });
}
class DelayProfile extends Component {
@@ -85,7 +85,7 @@ class DelayProfile extends Component {
connectDragSource
} = this.props;
let preferred = `Prefer ${titleCase(preferredProtocol)}`;
let preferred = titleCase(translate('PreferProtocol', { preferredProtocol }));
if (!enableUsenet) {
preferred = translate('OnlyTorrent');

View File

@@ -70,7 +70,7 @@ class DelayProfiles extends Component {
<Measure onMeasure={this.onMeasure}>
<FieldSet legend={translate('DelayProfiles')}>
<PageSectionContent
errorMessage={translate('UnableToLoadDelayProfiles')}
errorMessage={translate('DelayProfilesLoadError')}
{...otherProps}
>
<Scroller

View File

@@ -87,9 +87,9 @@ function EditDelayProfileModalContent(props) {
{
!isFetching && !!error ?
<div>
{translate('UnableToAddANewQualityProfilePleaseTryAgain')}
</div> :
<Alert kind={kinds.DANGER}>
{translate('AddDelayProfileError')}
</Alert> :
null
}
@@ -186,7 +186,7 @@ function EditDelayProfileModalContent(props) {
{
id === 1 ?
<Alert>
{translate('DefaultDelayProfile')}
{translate('DefaultDelayProfileMovie')}
</Alert> :
<FormGroup>
@@ -196,7 +196,7 @@ function EditDelayProfileModalContent(props) {
type={inputTypes.TAG}
name="tags"
{...tags}
helpText={translate('TagsHelpText')}
helpText={translate('DelayProfileMovieTagsHelpText')}
onChange={onInputChange}
/>
</FormGroup>

View File

@@ -8,6 +8,7 @@ import translate from 'Utilities/String/translate';
import DelayProfilesConnector from './Delay/DelayProfilesConnector';
import QualityProfilesConnector from './Quality/QualityProfilesConnector';
import ReleaseProfilesConnector from './Release/ReleaseProfilesConnector';
// Only a single DragDrop Context can exist so it's done here to allow editing
// quality profiles and reordering delay profiles to work.
@@ -19,9 +20,7 @@ class Profiles extends Component {
render() {
return (
<PageContent title={translate('Profiles')}>
<SettingsToolbarConnector
showSave={false}
/>
<SettingsToolbarConnector showSave={false} />
<PageContentBody>
<DndProvider options={HTML5toTouch}>

View File

@@ -158,7 +158,7 @@ class EditQualityProfileModalContent extends Component {
{
!isFetching && !!error &&
<div>
{translate('UnableToAddANewQualityProfilePleaseTryAgain')}
{translate('AddQualityProfileError')}
</div>
}
@@ -191,7 +191,7 @@ class EditQualityProfileModalContent extends Component {
type={inputTypes.CHECK}
name="upgradeAllowed"
{...upgradeAllowed}
helpText={translate('UpgradeAllowedHelpText')}
helpText={translate('UpgradesAllowedHelpText')}
onChange={onInputChange}
/>
</FormGroup>
@@ -200,7 +200,7 @@ class EditQualityProfileModalContent extends Component {
upgradeAllowed.value &&
<FormGroup size={sizes.EXTRA_SMALL}>
<FormLabel size={sizes.SMALL}>
{translate('UpgradeUntilQuality')}
{translate('UpgradeUntil')}
</FormLabel>
<FormInputGroup
@@ -208,7 +208,7 @@ class EditQualityProfileModalContent extends Component {
name="cutoff"
{...cutoff}
values={qualities}
helpText={translate('CutoffHelpText')}
helpText={translate('UpgradeUntilMovieHelpText')}
onChange={onCutoffChange}
/>
</FormGroup>
@@ -225,7 +225,7 @@ class EditQualityProfileModalContent extends Component {
type={inputTypes.NUMBER}
name="minFormatScore"
{...minFormatScore}
helpText={translate('MinFormatScoreHelpText')}
helpText={translate('MinimumCustomFormatScoreHelpText')}
onChange={onInputChange}
/>
</FormGroup>
@@ -242,7 +242,7 @@ class EditQualityProfileModalContent extends Component {
type={inputTypes.NUMBER}
name="cutoffFormatScore"
{...cutoffFormatScore}
helpText={translate('CutoffFormatScoreHelpText')}
helpText={translate('UpgradeUntilCustomFormatScoreMovieHelpText')}
onChange={onInputChange}
/>
</FormGroup>
@@ -301,7 +301,7 @@ class EditQualityProfileModalContent extends Component {
className={styles.deleteButtonContainer}
title={
isInUse ?
translate('QualityProfileInUse') :
translate('QualityProfileInUseMovieListCollection') :
undefined
}
>

View File

@@ -4,7 +4,7 @@ import React, { Component } from 'react';
import FormGroup from 'Components/Form/FormGroup';
import FormInputHelpText from 'Components/Form/FormInputHelpText';
import FormLabel from 'Components/Form/FormLabel';
import Link from 'Components/Link/Link';
import InlineMarkdown from 'Components/Markdown/InlineMarkdown';
import { sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import QualityProfileFormatItem from './QualityProfileFormatItem';
@@ -67,10 +67,7 @@ class QualityProfileFormatItems extends Component {
if (profileFormatItems.length < 1) {
return (
<div className={styles.addCustomFormatMessage}>
{translate('MoreControlCFText')}
<Link to='/settings/customformats'> {translate('CustomFormat')} </Link>
</div>
<InlineMarkdown className={styles.addCustomFormatMessage} data={translate('WantMoreControlAddACustomFormat')} />
);
}

View File

@@ -54,7 +54,7 @@ class QualityProfiles extends Component {
return (
<FieldSet legend={translate('QualityProfiles')}>
<PageSectionContent
errorMessage={translate('UnableToLoadQualityProfiles')}
errorMessage={translate('QualityProfilesLoadError')}
{...otherProps}c={true}
>
<div className={styles.qualityProfiles}>

View File

@@ -41,7 +41,7 @@ function EditReleaseProfileModalContent(props) {
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>
{id ? translate('Edit Release Profile') : translate('Add Release Profile')}
{id ? translate('EditReleaseProfile') : translate('AddReleaseProfile')}
</ModalHeader>
<ModalBody>
@@ -54,7 +54,7 @@ function EditReleaseProfileModalContent(props) {
type={inputTypes.TEXT}
name="name"
{...name}
placeholder="Optional name"
placeholder={translate('OptionalName')}
canEdit={true}
onChange={onInputChange}
/>
@@ -66,7 +66,7 @@ function EditReleaseProfileModalContent(props) {
<FormInputGroup
type={inputTypes.CHECK}
name="enabled"
helpText="Check to enable release profile"
helpText={translate('EnableProfileHelpText')}
{...enabled}
onChange={onInputChange}
/>
@@ -80,9 +80,9 @@ function EditReleaseProfileModalContent(props) {
inputClassName={styles.tagInternalInput}
type={inputTypes.TEXT_TAG}
name="required"
helpText="The release must contain at least one of these terms (case insensitive)"
helpText={translate('MustContainHelpText')}
kind={kinds.SUCCESS}
placeholder={translate('RequiredRestrictionPlaceHolder')}
placeholder={translate('AddNewRestriction')}
delimiters={tagInputDelimiters}
canEdit={true}
onChange={onInputChange}
@@ -97,9 +97,9 @@ function EditReleaseProfileModalContent(props) {
inputClassName={styles.tagInternalInput}
type={inputTypes.TEXT_TAG}
name="ignored"
helpText="The release will be rejected if it contains one or more of terms (case insensitive)"
helpText={translate('MustNotContainHelpText')}
kind={kinds.DANGER}
placeholder={translate('IgnoredPlaceHolder')}
placeholder={translate('AddNewRestriction')}
delimiters={tagInputDelimiters}
canEdit={true}
onChange={onInputChange}
@@ -112,8 +112,8 @@ function EditReleaseProfileModalContent(props) {
<FormInputGroup
type={inputTypes.INDEXER_SELECT}
name="indexerId"
helpText="Specify what indexer the profile applies to"
helpTextWarning="Using a specific indexer with release profiles can lead to duplicate releases being grabbed"
helpText={translate('ReleaseProfileIndexerHelpText')}
helpTextWarning={translate('ReleaseProfileIndexerHelpTextWarning')}
{...indexerId}
includeAny={true}
onChange={onInputChange}
@@ -126,7 +126,7 @@ function EditReleaseProfileModalContent(props) {
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText="Release profiles will apply to movies with at least one matching tag. Leave blank to apply to all movies"
helpText={translate('ReleaseProfileTagMovieHelpText')}
{...tags}
onChange={onInputChange}
/>

View File

@@ -5,6 +5,7 @@ import Label from 'Components/Label';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import TagList from 'Components/TagList';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import EditReleaseProfileModalConnector from './EditReleaseProfileModalConnector';
import styles from './ReleaseProfile.css';
@@ -137,7 +138,7 @@ class ReleaseProfile extends Component {
kind={kinds.DISABLED}
outline={true}
>
Disabled
{translate('Disabled')}
</Label>
}
@@ -162,9 +163,9 @@ class ReleaseProfile extends Component {
<ConfirmModal
isOpen={isDeleteReleaseProfileModalOpen}
kind={kinds.DANGER}
title="Delete ReleaseProfile"
message={'Are you sure you want to delete this releaseProfile?'}
confirmLabel="Delete"
title={translate('DeleteReleaseProfile')}
message={translate('DeleteReleaseProfileMessageText', { name })}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteReleaseProfile}
onCancel={this.onDeleteReleaseProfileModalClose}
/>

View File

@@ -150,13 +150,13 @@ class QualityDefinition extends Component {
} = this.state;
const minBytes = minSize * 1024 * 1024;
const minSixty = `${formatBytes(minBytes * 60)}/h`;
const minSixty = `${formatBytes(minBytes * 60)}/${translate('HourShorthand')}`;
const preferredBytes = preferredSize * 1024 * 1024;
const preferredSixty = preferredBytes ? `${formatBytes(preferredBytes * 60)}/h` : translate('Unlimited');
const preferredSixty = preferredBytes ? `${formatBytes(preferredBytes * 60)}/${translate('HourShorthand')}` : translate('Unlimited');
const maxBytes = maxSize && maxSize * 1024 * 1024;
const maxSixty = maxBytes ? `${formatBytes(maxBytes * 60)}/h` : translate('Unlimited');
const maxSixty = maxBytes ? `${formatBytes(maxBytes * 60)}/${translate('HourShorthand')}` : translate('Unlimited');
return (
<div className={styles.qualityDefinition}>

View File

@@ -20,13 +20,13 @@ function QualityDefinitionLimits(props) {
return (
<div>
<div>
{translate('MinutesSixty', [sixty])}
{translate('MinutesSixty', { sixty })}
</div>
<div>
{translate('MinutesNinety', [ninety])}
{translate('MinutesNinety', { ninety })}
</div>
<div>
{translate('MinutesHundredTwenty', [hundredTwenty])}
{translate('MinutesHundredTwenty', { hundredTwenty })}
</div>
</div>
);

View File

@@ -21,7 +21,7 @@ class QualityDefinitions extends Component {
return (
<FieldSet legend={translate('QualityDefinitions')}>
<PageSectionContent
errorMessage={translate('UnableToLoadQualityDefinitions')}
errorMessage={translate('QualityDefinitionsLoadError')}
{...otherProps}
>
<div className={styles.header}>
@@ -60,7 +60,7 @@ class QualityDefinitions extends Component {
<div className={styles.sizeLimitHelpTextContainer}>
<div className={styles.sizeLimitHelpText}>
{translate('QualityLimitsHelpText')}
{translate('QualityLimitsMovieRuntimeHelpText')}
</div>
</div>
</PageSectionContent>

Some files were not shown because too many files have changed in this diff Show More