1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-03-24 17:25:22 -04:00

Compare commits

...

120 Commits

Author SHA1 Message Date
Bogdan
6ad9ebb19e Revert "Fixed: Ensure translations are fetched before loading app"
This reverts commit c61cca7952.
2023-07-16 03:57:28 +03:00
Bogdan
f8cbca7958 New: Show tooltips with Custom Formats in History and Queue
(cherry picked from commit d6aee683dc4e8a8c94993b30df21fe8f6c5106b3)

Closes #8819
2023-07-16 03:41:42 +03:00
jack-mil
f65835b874 New: Add Custom Format fields to Discord On Grab notifications
(cherry picked from commit 3a9182b6a6a322a03666592f8e08d4afde11ee86)

Closes #8790
2023-07-16 03:25:18 +03:00
Bogdan
59ea905e06 Move ApplyTags to own file
Closes #8808
2023-07-16 03:19:26 +03:00
Mark McDowall
d8eda4d089 Fixed: Order of Discord grab notification fields
(cherry picked from commit 35e171f7b120ba68f4c2f5a7ada5ba204caf7f45)

Closes #8820
2023-07-16 03:14:35 +03:00
Mark McDowall
e4eb8f63bb Use named keys for apply tags help text
(cherry picked from commit c1f8c7b17ba5775a0f6f76cebc3173e03124d000)

Closes #8816
2023-07-16 03:14:10 +03:00
Bogdan
d936591b66 Fix translation call for OrganizeConfirm 2023-07-16 03:08:33 +03:00
Mark McDowall
c61cca7952 Fixed: Ensure translations are fetched before loading app
(cherry picked from commit ad2721dc55f3233e4c299babe5744418bc530418)

Closes #8814
Closes #8817
2023-07-16 03:03:57 +03:00
Ricardo Christmann
f38077aac7 New: Add pushsafer notification service (#8770) 2023-07-14 21:22:08 -05:00
Weblate
3055ed5336 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-07-14 05:22:54 +03:00
Servarr
164625a0b2 Automated API Docs update 2023-07-11 18:42:00 +03:00
Qstick
09ca0a1c0a New: Download Client Tags
(cherry picked from commit f6ae9fd6c5173cbf1540341fa99d2f120be1d28e)
2023-07-11 18:34:02 +03:00
Weblate
bef881a9e2 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-07-11 11:04:23 +03:00
Servarr
f7e36581e1 Automated API Docs update 2023-07-11 11:04:00 +03:00
jack-mil
20a8f1cbe7 New: Custom Format Score column in queue
(cherry picked from commit a6f2db9139c4a6b01d162ccf8884fc02c874b4cf)

Closes #8788
2023-07-11 10:56:56 +03:00
Qstick
3da8396b7e Fix circular dependency with ScriptImportDecider, TagService 2023-07-11 00:11:33 -05:00
bakerboy448
d61f914bd7 Fixed: Improve Kodi Library Update logging 2023-07-10 23:30:44 -05:00
Bakerboy448
25837adfc7 More Import List Logging Improvements 2023-07-10 23:29:54 -05:00
Qstick
5516d7e3cd Fixed: Fade out on hover of collection movies in dark mode 2023-07-10 23:29:16 -05:00
Qstick
e2647deea3 Fixed: Default new lists to 'Released' minimum availability in UI 2023-07-10 23:18:59 -05:00
Jendrik Weise
8c34946134 New: Additional info passed in for Script Import and Custom Script
(cherry picked from commit 3f0268b79f6f5953191da4a765ba24159e15974d)
2023-07-10 23:04:47 -05:00
Qstick
4a66a832b3 New: View, Sort, Filter by Movie popularity on Index and Discover
Fixes #1947
2023-07-10 22:54:32 -05:00
Qstick
2d18e4f89e Fixed: Multiple settings not working on Movie Overview view 2023-07-10 21:57:26 -05:00
Qstick
d6c1721f51 Sonarr to Radarr in Freebox download client settings 2023-07-10 21:34:58 -05:00
Qstick
99709d6445 Add missing HistoryTable css type file 2023-07-10 21:34:07 -05:00
Qstick
916d43d70d New: Simkl List Support
(cherry picked from commit 4a740acb801a04bc2ead45d272d493f4ec46f7e8)
2023-07-10 21:34:07 -05:00
Bogdan
bc004b3b5b Improve look of no history message 2023-07-11 03:32:53 +03:00
Servarr
7a222dcd9f Automated API Docs update 2023-07-10 23:42:02 +03:00
Bogdan
48b9c1e8b9 Fixed: Minor improvements and translations for managing bulk indexers, lists and clients 2023-07-10 23:34:01 +03:00
Bogdan
7dde88387a Fix build removing trailing spaces 2023-07-10 20:57:51 +03:00
bakerboy448
0eddf76622 Fixed: Further clarification to Quality Profile Cut Offs 2023-07-10 19:52:44 +03:00
Bogdan
f69a847d9a Apply suggestions from code review 2023-07-10 19:51:57 +03:00
Bogdan
97ed820575 Apply suggestions from code review 2023-07-10 19:51:57 +03:00
Bogdan
0ee94a4624 Update src/NzbDrone.Core/ImportLists/FetchAndParseImportListService.cs 2023-07-10 19:51:57 +03:00
bakerboy448
3b7914f63b New: Import List Logging Improvements 2023-07-10 19:51:57 +03:00
Weblate
0005fa57ac Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-07-10 19:24:14 +03:00
Qstick
bbde1dc7a6 Avoid using GetAllMovies in MediaFileDeletionService 2023-07-09 23:32:53 -05:00
Qstick
1c99ce8876 Avoid using GetAllMovies in DeleteBadMediaCovers 2023-07-09 23:32:53 -05:00
Qstick
7a5ae56a96 Fixed: Skip move when source and destination are the same
Co-Authored-By: Colin Hebert <makkhdyn@gmail.com>
2023-07-09 23:08:05 -05:00
Qstick
ae8820178d Avoid db call for naming config on every movie during single collection call 2023-07-09 23:05:59 -05:00
ricci2511
c214a6b67b Fixed: Handle client state of collection missingMovies 2023-07-09 11:15:51 -05:00
Bogdan
b3f6774820 Bump version to 4.7.1 2023-07-09 15:00:20 +03:00
Bogdan
8fd4e41c85 Add translations for tags in manage indexers 2023-07-08 00:38:49 +03:00
Weblate
8984fd735b Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Kevin Orel Edry <techg9@gmail.com>
Co-authored-by: Tacit <1750630216@qq.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: 阿卡林刘 <ScottLiu_NonWin@outlook.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-07-08 00:10:34 +03:00
Bogdan
3321123043 Fix translation to Apply Changes 2023-07-08 00:04:17 +03:00
Bogdan
23a13b5c23 Use SetProviderCharacteristics in bulk endpoint 2023-07-08 00:00:08 +03:00
Bogdan
304a07e23f Add translation to manage indexers 2023-07-07 20:19:32 +03:00
Bogdan
1e0ec4aefb Fix tests in ImportListSyncServiceFixture 2023-07-05 09:22:32 +03:00
Bogdan
5c46c75ce7 Fix cleaning library in ImportListSyncService 2023-07-05 09:01:53 +03:00
Bogdan
1c26dd4aca Disable library cleanup temporarily 2023-07-05 08:31:41 +03:00
Weblate
6fae00f51c 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
2023-07-05 08:11:15 +03:00
Servarr
653ef0a501 Automated API Docs update 2023-07-04 13:03:49 -05:00
Qstick
e606ff05a4 Add package to Sentry release to ensure apps don't mix 2023-07-04 12:12:44 -05:00
Agneev Mukherjee
dd3ac26604 Set frontend theme-color to sidebar color (#6891) 2023-07-04 11:32:42 -05:00
Bakerboy448
122d0056ea Fixed: Quality Parsing Regex Improvements
Fixed: Parse Blu.Ray as Bluray
2023-07-04 11:20:51 -05:00
Ricardo Christmann
fe41aada06 New: Add tags field to MovieCollection (#8736)
* New: Add tags field to MovieCollection
* Added Tag input prepopulation for new collection movies
* Handle editting of collection tags
* Revert changes to CollectionController.cs
2023-07-04 11:18:44 -05:00
Bogdan
bd1844030d New: Rework List sync interval logic
* New: Rework List sync interval logic

(cherry picked from commit c522cd120d08757e7e43c2348be4d7f05a254fac)

* Minor alignment with Sonarr

* Remove ListUpdateInterval

---------

Co-authored-by: Qstick <qstick@gmail.com>
2023-07-04 19:17:28 +03:00
Qstick
148ee5983d Bump version to 4.7.0 2023-07-03 22:29:48 -05:00
Qstick
372d15ecf3 New DSN for 4.6 2023-07-03 11:16:06 -05:00
Bogdan
b95431500d Fixed: Sorting queue by year
Fixes #8765
2023-07-03 17:00:14 +03:00
Bogdan
3da72f54ef Add ContentSummary to HDBits requests
(cherry picked from commit b6f3bcb3093267c483a57e10ac425e871f1f7ba8)

Closes #8757
2023-07-03 11:22:43 +03:00
Bogdan
7cfff20cad Create overload for ToJson() with Formatting param
(cherry picked from commit aa2b0031671b6846eaa75e0914cd03ae7bbb0da7)
2023-07-03 11:20:02 +03:00
Qstick
d3895dec8f Fixed: Allow restore to process backups up to ~500MB
(cherry picked from commit 551edb9e655d2a541a2232f85e79a5e3f7b433aa)
2023-07-03 08:55:11 +01:00
Weblate
690bab3264 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: BeardedWatermelon <periklis.karantonis@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translation: Servarr/Radarr
2023-06-30 13:55:34 +03:00
Bogdan
986128e100 Removed suspicious URL in the default definitions
Co-authored-by: Rumplin <35449956+rumplin@users.noreply.github.com>
2023-06-29 18:06:04 +03:00
Weblate
dda0885f91 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1185 of 1185 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-06-28 13:55:21 +03:00
Mark McDowall
7e218a886d Handle null for parent name with clean path is empty
(cherry picked from commit bd3816dac9b540d2f95960a254bb21ab3c91421e)
2023-06-28 08:27:19 +03:00
Mark McDowall
77cde138dc Fixed: Don't handle images in metadata folder as Roksbox images
(cherry picked from commit 95a8f59a32d55550d5367f08a964859a97a0df44)
2023-06-28 08:27:19 +03:00
Bogdan
239109e3dd New: Improve empty list messaging
(cherry picked from commit ee843259bca2d9764a3919b123524a51a3a16cce)

Closes #8738
2023-06-27 06:00:03 +03:00
Bogdan
4804eb0769 Fixed: Invalid image URL if Movie is missing background image
(cherry picked from commit dd096e0fda71b3afa9b09c2900abbf226d8a5204)

Closes #8742
2023-06-27 05:46:30 +03:00
Bogdan
60a55dfdac Allow array of string as value in EnhancedSelectInput
(cherry picked from commit 6816767fad9e4e839e77c5fe40aece97033cd052)
2023-06-26 23:49:23 +01:00
Servarr
cd82865303 Automated API Docs update 2023-06-26 02:25:31 +03:00
Servarr
439adb4ac6 Translated using Weblate (Hungarian) [skip ci] (#8734)
Currently translated at 97.6% (1156 of 1184 strings)


Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translation: Servarr/Radarr

Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: sutoramon <sutoramon@gmail.com>
2023-06-26 02:25:08 +03:00
Bogdan
fd0ff78791 Add translation to movie collection filters 2023-06-26 02:23:26 +03:00
Ricardo Christmann
cbae355402 New: Added filter and sort options to Collections (#8731)
* New: Added filter and sort options to Collections

* Add AllMovieWithCollectionsTmdbIds method to MovieService and MovieRepository
2023-06-25 10:04:57 -04:00
Qstick
fed98a648f Bump version to 4.6.4 2023-06-25 01:10:05 -04:00
bakerboy448
e1c5656cff Add more trace logs related info to bug_report.yml [skip ci] [common] 2023-06-22 16:38:09 +03:00
Weblate
e3f88e1711 Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1184 of 1184 strings)

Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]

Currently translated at 9.2% (109 of 1184 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1184 of 1184 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 87.6% (1038 of 1184 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1184 of 1184 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: KHng0284 <giakhang021109@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: ted09080037 <ted09080037@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_TW/
Translation: Servarr/Radarr
2023-06-21 06:53:25 +03:00
Servarr
8fd267580a Automated API Docs update 2023-06-21 06:45:42 +03:00
Bogdan
8974aa823b Remove not implemented endpoints from API docs
Closes #8724
2023-06-21 06:34:07 +03:00
Bogdan
41492efd2e Convert to 'using' declaration in Housekeeping Tasks
Closes #8723
2023-06-21 06:25:44 +03:00
Bogdan
d008768fff Prevent NullRef when deleting missing backups
(cherry picked from commit 0ff0fe2e68f3abf7b8e4d6bf0c1e9dee4eb68227)

Closes #8721
2023-06-21 06:19:30 +03:00
Bogdan
cb21fe535d Fix translation for Unreleased 2023-06-20 19:39:16 +03:00
Bogdan
4cce2727e2 Update translations
(cherry picked from commit 26031389757f6b5270bbe5591101b08e58debb73)
2023-06-20 02:38:55 +03:00
Stevie Robinson
b1ff82da37 Fixed: Parsing Vyndros as release group
(cherry picked from commit f2ddd4757c897c522b553de8bafb5340746253c9)

Closes #8569
2023-06-19 07:09:04 +03:00
Mark McDowall
c5266152c5 Fixed: Strip additional domains from release names
(cherry picked from commit e273f16c3905e0c2451f43cf98b9b7ad1cbdc777)

Closes #8603
2023-06-19 07:00:22 +03:00
Bogdan
783878be1e Minor improvements in health checks
(cherry picked from commit a22f598b0c129110f2a3b663e9b40c84f3a1f02b)

Closes #8615
2023-06-19 06:38:51 +03:00
Bogdan
0cbfb4ca65 New: (UI) Search library by imdbId and tmdbId 2023-06-19 04:19:12 +03:00
bakerboy448
c22c9400c2 New: Indexer Messaging and Error Improvements
(cherry picked from commit 3b505d8734dcbe3fa53acba7f94f1361151e6a44)
2023-06-18 12:06:55 +03:00
Bogdan
0288c4b704 Bump version to 4.6.3 2023-06-18 12:05:11 +03:00
Márki-Zay Ferenc
e4429d2919 Fixed: Close database connection in housekeeping tasks 2023-06-17 03:52:12 +03:00
Bogdan
7052a7a5ec New: Improved page loading errors
Closes #8706
2023-06-16 23:45:26 +03:00
Weblate
b38912851b Translated using Weblate (Portuguese (Brazil)) [skip ci]
Currently translated at 100.0% (1184 of 1184 strings)

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-06-16 02:21:40 +03:00
Bogdan
1354c2c337 Fix sorting history items by movie titles 2023-06-15 23:21:16 +03:00
Servarr
e259235df6 Automated API Docs update 2023-06-14 09:17:16 +03:00
Bogdan
0cc1fe8308 Add HelpTextWarning support in FieldDefinition
(cherry picked from commit 0e07d54ee77d5f83716e17b6757e23f38ff73694)

Closes #8687
2023-06-14 07:55:44 +03:00
Bogdan
f4fe18a440 Require ApiKey for all actions in RadarrImport
(cherry picked from commit 19b8fbe13bf584b915a05fe9fc87622adbaee0b7)

Closes #8692
2023-06-14 07:50:53 +03:00
Bogdan
eeed935e3a Update cleansing rules for RSS TL feed and homedir for Mac
(cherry picked from commit e5ff4aafa3f0b855fec332788e9fc490a03dfce3)

Closes #8684
2023-06-14 07:48:26 +03:00
Bogdan
1b3701371a Fixed: Treat redirects as errors in Radarr Import List
(cherry picked from commit 059a156f4a34c6b9cbe139fa1973b814e8a534ae)
2023-06-14 07:40:06 +03:00
Qstick
d56f3ec2e7 Fixed: Correctly handle 302 and 303 redirects in HttpClient
(cherry picked from commit ed7c5a937f4b50fcdf819e8fe347c8c0bc6bd2e7)

(cherry picked from commit 11bd764a75d3b97117098738d3489c4b3329738f)
2023-06-14 07:37:37 +03:00
Weblate
e7e3aac971 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Update translation files  [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 97.5% (1155 of 1184 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.1% (262 of 1184 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 97.8% (1158 of 1184 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1184 of 1184 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.5% (1179 of 1184 strings)

Update translation files  [skip ci]

Updated by "Cleanup translation files" hook in Weblate.

Translated using Weblate (Indonesian) [skip ci]

Currently translated at 7.5% (89 of 1180 strings)

Translated using Weblate (Croatian) [skip ci]

Currently translated at 21.8% (258 of 1180 strings)

Translated using Weblate (Ukrainian) [skip ci]

Currently translated at 97.9% (1156 of 1180 strings)

Translated using Weblate (Slovak) [skip ci]

Currently translated at 21.1% (249 of 1180 strings)

Translated using Weblate (Norwegian Bokmål) [skip ci]

Currently translated at 22.2% (263 of 1180 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (Arabic) [skip ci]

Currently translated at 88.8% (1048 of 1180 strings)

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 98.8% (1166 of 1180 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 99.9% (1179 of 1180 strings)

Translated using Weblate (Thai) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Bulgarian) [skip ci]

Currently translated at 86.2% (1018 of 1180 strings)

Translated using Weblate (Hindi) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Romanian) [skip ci]

Currently translated at 85.9% (1014 of 1180 strings)

Translated using Weblate (Vietnamese) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Turkish) [skip ci]

Currently translated at 88.1% (1040 of 1180 strings)

Translated using Weblate (Swedish) [skip ci]

Currently translated at 89.0% (1051 of 1180 strings)

Translated using Weblate (Russian) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.3% (1160 of 1180 strings)

Translated using Weblate (Polish) [skip ci]

Currently translated at 97.1% (1146 of 1180 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 98.4% (1162 of 1180 strings)

Translated using Weblate (Korean) [skip ci]

Currently translated at 21.3% (252 of 1180 strings)

Translated using Weblate (Japanese) [skip ci]

Currently translated at 88.2% (1041 of 1180 strings)

Translated using Weblate (Icelandic) [skip ci]

Currently translated at 88.3% (1042 of 1180 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 98.1% (1158 of 1180 strings)

Translated using Weblate (Hebrew) [skip ci]

Currently translated at 91.2% (1077 of 1180 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 97.9% (1156 of 1180 strings)

Translated using Weblate (Greek) [skip ci]

Currently translated at 99.6% (1176 of 1180 strings)

Translated using Weblate (Danish) [skip ci]

Currently translated at 88.3% (1042 of 1180 strings)

Translated using Weblate (Czech) [skip ci]

Currently translated at 89.1% (1052 of 1180 strings)

Translated using Weblate (Italian) [skip ci]

Currently translated at 93.8% (1107 of 1180 strings)

Translated using Weblate (Spanish) [skip ci]

Currently translated at 98.2% (1159 of 1180 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.4% (1173 of 1180 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 99.9% (1179 of 1180 strings)

Co-authored-by: Anonymous <noreply@weblate.org>
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/ar/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/bg/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/da/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
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/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/id/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/is/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ja/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ko/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nb_NO/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ro/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/sv/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/th/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/tr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/vi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-06-14 07:37:13 +03:00
Bogdan
d2cb36c88a Check only clients not in failure status in DownloadClientSortingCheck
(cherry picked from commit 0b872803358bac1297cc7618ea3c13a32a92b5a4)
2023-06-14 07:34:21 +03:00
bakerboy448
2fe28cb1dc Fixed: Handle checkingResumeData state form qBittorrent
(cherry picked from commit 8d8a16225ff7772ccb57784f272ca31e28bb8455)
2023-06-14 07:33:55 +03:00
Bogdan
5d65b4cae4 Fix sorting queue items by size 2023-06-14 04:46:19 +03:00
Bogdan
b0f56e2840 Update translations 2023-06-13 02:03:51 +03:00
Weblate
5593837482 Update translation files [skip ci]
Updated by "Cleanup translation files" hook in Weblate.

Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translation: Servarr/Radarr
2023-06-13 01:40:09 +03:00
Qstick
8231290c7b Update Remote Path Mapping delete modal title
(cherry picked from commit 18716a00516a971f7f2eb369b920266bea24fe08)

Closes #8675
2023-06-12 22:52:50 +03:00
Weblate
0c1b88c60a Translated using Weblate (Indonesian) [skip ci]
Currently translated at 7.3% (87 of 1179 strings)

Co-authored-by: liimee <git.taaa@fedora.email>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/id/
Translation: Servarr/Radarr
2023-06-12 11:49:17 +03:00
Qstick
0b8478e4a1 Bump version to 4.6.2 2023-06-11 09:39:17 -05:00
Weblate
69e09c8687 Translated using Weblate (Russian) [skip ci]
Currently translated at 98.3% (1159 of 1179 strings)

Co-authored-by: Андрей <andryfly7@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ru/
Translation: Servarr/Radarr
2023-06-10 22:43:53 +03:00
Bogdan
3f2ea49023 Add style for default kind in ProgressBar 2023-06-10 03:13:47 +03:00
Bogdan
32f09633e9 Use more specific styling for kinds in ProgressBar
(cherry picked from commit dd31c913d2a974d95f3be251714ce749cfd99a72)

Fixes #8669
2023-06-10 01:45:40 +03:00
Qstick
3542b263c7 Fixed: Don't die on movie refresh when collection has been deleted from TMDB
Fixes #8664
2023-06-07 20:12:59 -05:00
Weblate
d5cc84d8c8 Translated using Weblate (Greek) [skip ci]
Currently translated at 99.5% (1174 of 1179 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.4% (1172 of 1179 strings)

Translated using Weblate (Portuguese) [skip ci]

Currently translated at 98.3% (1159 of 1179 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1179 of 1179 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1179 of 1179 strings)

Co-authored-by: MoowGlax <matthieu.derouet.pro@gmail.com>
Co-authored-by: Thodoris Kalatzis <teo.kal@hotmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: emacsdias <emacs.dias@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: splifter <a.strahlke@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt/
Translation: Servarr/Radarr
2023-06-07 17:57:09 +03:00
Bogdan
c0790060fb Fixed: (UI) Sort last movies with no release dates
Towards #8662
2023-06-07 06:52:12 +03:00
Bogdan
5ec7e86488 Add language names as hints in TMDbSettings
Add Romanian in TMDb Language Codes
Move DateTime.TryParse to if condition in TMDbParser
2023-06-05 22:17:32 +03:00
Qstick
b8abafd72f Bump version to 4.6.1 2023-06-04 11:43:43 -05:00
Bogdan
a471f1b44f Bump NLog to 5.2.0 2023-06-02 07:50:34 +03:00
Weblate
7fe34be789 Update translation files [skip ci]
Updated by "Remove blank strings" hook in Weblate.

Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]

Currently translated at 98.8% (1166 of 1179 strings)

Translated using Weblate (Portuguese (Brazil)) [skip ci]

Currently translated at 100.0% (1179 of 1179 strings)

Translated using Weblate (Dutch) [skip ci]

Currently translated at 98.5% (1162 of 1179 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 99.3% (1171 of 1179 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 98.6% (1163 of 1179 strings)

Co-authored-by: Cc95459 <954591059@qq.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Jens <jensmahnke@me.com>
Co-authored-by: Thijs Waalen <contact@thijswaalen.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: foXaCe <foxace66@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-06-01 02:00:11 +03:00
Zak Saunders
471a34eabf New: Remove Rarbg Indexer due to site shutdown 2023-05-31 16:20:11 +01:00
338 changed files with 3816 additions and 2800 deletions

View File

@@ -76,7 +76,7 @@ body:
- type: checkboxes
attributes:
label: Trace Logs have been provided as applicable. Reports may be closed if the required logs are not provided.
description: Trace logs are generally required for all bug reports
description: Trace logs are generally required for all bug reports and contain `trace`. Info logs are invalid for bug reports and do not contain `debug` nor `trace`
options:
- label: I have followed the steps in the wiki link above and provided the required trace logs that are relevant and show this issue.
- label: I have read and followed the steps in the wiki link above and provided the required trace logs - the logs contain `trace` - that are relevant and show this issue.
required: true

View File

@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '4.6.0'
majorVersion: '4.7.1'
minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
@@ -363,7 +363,7 @@ stages:
- bash: |
echo "Uploading source maps to sentry"
curl -sL https://sentry.io/get-cli/ | bash
RELEASENAME="${RADARRVERSION}-${BUILD_SOURCEBRANCHNAME}"
RELEASENAME="Radarr@${RADARRVERSION}-${BUILD_SOURCEBRANCHNAME}"
sentry-cli releases new --finalize -p radarr -p radarr-ui -p radarr-update "${RELEASENAME}"
sentry-cli releases -p radarr-ui files "${RELEASENAME}" upload-sourcemaps _output/UI/ --rewrite
sentry-cli releases set-commits --auto "${RELEASENAME}"

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import PageContent from 'Components/Page/PageContent';
@@ -156,16 +157,16 @@ class Blocklist extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadBlocklist')}
</div>
</Alert>
}
{
isPopulated && !error && !items.length &&
<div>
{translate('NoHistory')}
</div>
<Alert kind={kinds.INFO}>
{translate('NoHistoryBlocklist')}
</Alert>
}
{
@@ -209,7 +210,7 @@ class Blocklist extends Component {
isOpen={isConfirmRemoveModalOpen}
kind={kinds.DANGER}
title={translate('RemoveSelected')}
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist')}
message={translate('RemoveSelectedItemBlocklistMessageText')}
confirmLabel={translate('RemoveSelected')}
onConfirm={this.onRemoveSelectedConfirmed}
onCancel={this.onConfirmRemoveModalClose}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import FilterMenu from 'Components/Menu/FilterMenu';
import PageContent from 'Components/Page/PageContent';
@@ -11,7 +12,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import HistoryRowConnector from './HistoryRowConnector';
@@ -83,9 +84,9 @@ class History extends Component {
{
!isFetchingAny && hasError &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadHistory')}
</div>
</Alert>
}
{
@@ -93,9 +94,9 @@ class History extends Component {
// wait for the episodes to populate because they are never coming.
isPopulated && !hasError && !items.length &&
<div>
<Alert kind={kinds.INFO}>
{translate('NoHistory')}
</div>
</Alert>
}
{

View File

@@ -4,12 +4,13 @@ import IconButton from 'Components/Link/IconButton';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow';
import { icons } from 'Helpers/Props';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, tooltipPositions } from 'Helpers/Props';
import MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality';
import MovieTitleLink from 'Movie/MovieTitleLink';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
import HistoryDetailsModal from './Details/HistoryDetailsModal';
import HistoryEventTypeCell from './HistoryEventTypeCell';
import styles from './HistoryRow.css';
@@ -176,7 +177,14 @@ class HistoryRow extends Component {
key={name}
className={styles.customFormatScore}
>
{formatCustomFormatScore(customFormatScore)}
<Tooltip
anchor={formatPreferredWordScore(
customFormatScore,
customFormats.length
)}
tooltip={<MovieFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
@@ -257,4 +265,8 @@ HistoryRow.propTypes = {
onMarkAsFailedPress: PropTypes.func.isRequired
};
HistoryRow.defaultProps = {
customFormats: []
};
export default HistoryRow;

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -12,7 +13,7 @@ import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import TablePager from 'Components/Table/TablePager';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import getRemovedItems from 'Utilities/Object/getRemovedItems';
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
import translate from 'Utilities/String/translate';
@@ -231,17 +232,17 @@ class Queue extends Component {
{
!isRefreshing && hasError ?
<div>
<Alert kind={kinds.DANGER}>
{translate('FailedToLoadQueue')}
</div> :
</Alert> :
null
}
{
isAllPopulated && !hasError && !items.length ?
<div>
<Alert kind={kinds.INFO}>
{translate('QueueIsEmpty')}
</div> :
</Alert> :
null
}

View File

@@ -16,6 +16,12 @@
width: 150px;
}
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;
}
.actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css';

View File

@@ -2,6 +2,7 @@
// Please do not change this file!
interface CssExports {
'actions': string;
'customFormatScore': string;
'progress': string;
'protocol': string;
'quality': string;

View File

@@ -8,13 +8,15 @@ import ProgressBar from 'Components/ProgressBar';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow';
import { icons, kinds } from 'Helpers/Props';
import Tooltip from 'Components/Tooltip/Tooltip';
import { icons, kinds, tooltipPositions } from 'Helpers/Props';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality';
import MovieTitleLink from 'Movie/MovieTitleLink';
import formatBytes from 'Utilities/Number/formatBytes';
import formatPreferredWordScore from 'Utilities/Number/formatPreferredWordScore';
import translate from 'Utilities/String/translate';
import QueueStatusCell from './QueueStatusCell';
import RemoveQueueItemModal from './RemoveQueueItemModal';
@@ -88,6 +90,7 @@ class QueueRow extends Component {
movie,
quality,
customFormats,
customFormatScore,
languages,
protocol,
indexer,
@@ -201,6 +204,24 @@ class QueueRow extends Component {
);
}
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
<Tooltip
anchor={formatPreferredWordScore(
customFormatScore,
customFormats.length
)}
tooltip={<MovieFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
if (name === 'protocol') {
return (
<TableRowCell key={name}>
@@ -365,6 +386,7 @@ QueueRow.propTypes = {
movie: PropTypes.object,
quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
protocol: PropTypes.string.isRequired,
indexer: PropTypes.string,
@@ -390,6 +412,7 @@ QueueRow.propTypes = {
};
QueueRow.defaultProps = {
customFormats: [],
isGrabbing: false,
isRemoving: false
};

View File

@@ -88,7 +88,7 @@ class RemoveQueueItemsModal extends Component {
<ModalBody>
<div className={styles.message}>
{selectedCount > 1 ? translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', selectedCount) : translate('AreYouSureYouWantToRemoveSelectedItemFromQueue')}
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', selectedCount) : translate('RemoveSelectedItemQueueMessageText')}
</div>
{
@@ -133,7 +133,7 @@ class RemoveQueueItemsModal extends Component {
kind={kinds.DANGER}
onPress={this.onRemoveConfirmed}
>
Remove
{translate('Remove')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,9 +1,11 @@
import { reduce } from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import selectAll from 'Utilities/Table/selectAll';
import toggleSelected from 'Utilities/Table/toggleSelected';
@@ -105,9 +107,9 @@ class ImportMovie extends Component {
{
!rootFoldersFetching && !!rootFoldersError ?
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div> :
</Alert> :
null
}
@@ -116,9 +118,9 @@ class ImportMovie extends Component {
!rootFoldersFetching &&
rootFoldersPopulated &&
!unmappedFolders.length ?
<div>
<Alert kind={kinds.INFO}>
{translate('AllMoviesInPathHaveBeenImported', [path])}
</div> :
</Alert> :
null
}

View File

@@ -92,9 +92,9 @@ class ImportMovieSelectFolder extends Component {
{
!isFetching && error ?
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div> :
</Alert> :
null
}

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import AgendaConnector from './Agenda/AgendaConnector';
import * as calendarViews from './calendarViews';
@@ -31,9 +33,9 @@ class Calendar extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadTheCalendar')}
</div>
</Alert>
}
{

View File

@@ -28,7 +28,7 @@ function createMapStateToProps() {
qualityProfileId: collection.qualityProfileId,
minimumAvailability: collection.minimumAvailability,
searchForMovie: collection.searchOnAdd,
tags: []
tags: collection.tags || []
};
const {

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -9,7 +10,7 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import { align, icons, sortDirections } from 'Helpers/Props';
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
import styles from 'Movie/Index/MovieIndex.css';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
@@ -313,9 +314,9 @@ class Collection extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCollections')}
</div>
</Alert>
}
{

View File

@@ -2,17 +2,12 @@ import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector';
import createCollectionSelector from 'Store/Selectors/createCollectionSelector';
function createMapStateToProps() {
return createSelector(
createCollectionSelector(),
createAllMoviesSelector(),
(
collection,
allMovies
) => {
(collection) => {
// If a movie is deleted this selector may fire before the parent
// selecors, which will result in an undefined movie, if that happens
// we want to return early here and again in the render function to avoid
@@ -22,21 +17,11 @@ function createMapStateToProps() {
return {};
}
let allGenres = [];
let libraryMovies = 0;
collection.movies.forEach((movie) => {
allGenres = allGenres.concat(movie.genres);
if (allMovies.find((libraryMovie) => libraryMovie.tmdbId === movie.tmdbId)) {
libraryMovies++;
}
});
const allGenres = collection.movies.flatMap((movie) => movie.genres);
return {
...collection,
genres: Array.from(new Set(allGenres)).slice(0, 3),
missingMovies: collection.movies.length - libraryMovies
genres: Array.from(new Set(allGenres)).slice(0, 3)
};
}
);

View File

@@ -50,6 +50,7 @@ class EditCollectionModalContent extends Component {
minimumAvailability,
// Id,
rootFolderPath,
tags,
searchOnAdd
} = item;
@@ -126,6 +127,17 @@ class EditCollectionModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
name="tags"
onChange={onInputChange}
{...tags}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('SearchOnAdd')}</FormLabel>

View File

@@ -42,6 +42,7 @@ function createMapStateToProps() {
qualityProfileId: collection.qualityProfileId,
minimumAvailability: collection.minimumAvailability,
rootFolderPath: collection.rootFolderPath,
tags: collection.tags,
searchOnAdd: collection.searchOnAdd
};

View File

@@ -28,6 +28,14 @@ function CollectionSortMenu(props) {
>
{translate('Title')}
</SortMenuItem>
<SortMenuItem
name="missingMovies"
sortKey={sortKey}
sortDirection={sortDirection}
onPress={onSortSelect}
>
{translate('Missing')}
</SortMenuItem>
</MenuContent>
</SortMenu>
);

View File

@@ -102,7 +102,7 @@ $hoverScale: 1.05;
position: relative;
display: block;
background-color: var(--defaultColor);
background-color: var(--black);
}
.monitorToggleButton {

View File

@@ -580,7 +580,7 @@ EnhancedSelectInput.propTypes = {
className: PropTypes.string,
disabledClassName: PropTypes.string,
name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.arrayOf(PropTypes.number)]).isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.arrayOf(PropTypes.string), PropTypes.arrayOf(PropTypes.number)]).isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired,
isDisabled: PropTypes.bool.isRequired,
isFetching: PropTypes.bool.isRequired,

View File

@@ -63,6 +63,7 @@ function ProviderFieldFormGroup(props) {
name,
label,
helpText,
helpTextWarning,
helpLink,
placeholder,
value,
@@ -96,6 +97,7 @@ function ProviderFieldFormGroup(props) {
name={name}
label={label}
helpText={helpText}
helpTextWarning={helpTextWarning}
helpLink={helpLink}
placeholder={placeholder}
value={value}
@@ -122,6 +124,7 @@ ProviderFieldFormGroup.propTypes = {
name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired,
helpText: PropTypes.string,
helpTextWarning: PropTypes.string,
helpLink: PropTypes.string,
placeholder: PropTypes.string,
value: PropTypes.any,

View File

@@ -19,6 +19,8 @@ function createCleanMovieSelector() {
year,
images,
alternateTitles = [],
tmdbId,
imdbId,
tags = []
} = movie;
@@ -29,6 +31,8 @@ function createCleanMovieSelector() {
year,
images,
alternateTitles,
tmdbId,
imdbId,
firstCharacter: title.charAt(0).toLowerCase(),
tags: tags.reduce((acc, id) => {
const matchingTag = allTags.find((tag) => tag.id === id);

View File

@@ -12,6 +12,8 @@ function MovieSearchResult(props) {
year,
images,
alternateTitles,
tmdbId,
imdbId,
tags
} = props;
@@ -47,6 +49,22 @@ function MovieSearchResult(props) {
null
}
{
match.key === 'tmdbId' && tmdbId ?
<div className={styles.alternateTitle}>
TmdbId: {tmdbId}
</div> :
null
}
{
match.key === 'imdbId' && imdbId ?
<div className={styles.alternateTitle}>
ImdbId: {imdbId}
</div> :
null
}
{
tag ?
<div className={styles.tagContainer}>
@@ -69,6 +87,8 @@ MovieSearchResult.propTypes = {
year: PropTypes.number.isRequired,
images: PropTypes.arrayOf(PropTypes.object).isRequired,
alternateTitles: PropTypes.arrayOf(PropTypes.object).isRequired,
tmdbId: PropTypes.number,
imdbId: PropTypes.string,
tags: PropTypes.arrayOf(PropTypes.object).isRequired,
match: PropTypes.object.isRequired
};

View File

@@ -9,6 +9,8 @@ const fuseOptions = {
keys: [
'title',
'alternateTitles.title',
'tmdbId',
'imdbId',
'tags.label'
]
};

View File

@@ -1,6 +1,8 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { kinds } from 'Helpers/Props';
function PageSectionContent(props) {
const {
@@ -17,7 +19,7 @@ function PageSectionContent(props) {
);
} else if (!isFetching && !!error) {
return (
<div>{errorMessage}</div>
<Alert kind={kinds.DANGER}>{errorMessage}</Alert>
);
} else if (isPopulated && !error) {
return (

View File

@@ -16,6 +16,46 @@
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
color: var(--white);
transition: width 0.6s ease;
&.default {
background-color: var(--darkGray);
}
&.primary {
background-color: var(--primaryColor);
}
&.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
&.success {
background-color: var(--successColor);
}
&.purple {
background-color: var(--purple);
}
&.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
&.info {
background-color: var(--infoColor);
}
&.queue {
background-color: var(--queueColor);
}
}
.frontTextContainer {
@@ -45,46 +85,6 @@
cursor: default;
}
.default {
background-color: var(--darkGray);
}
.primary {
background-color: var(--primaryColor);
}
.danger {
background-color: var(--dangerColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
}
}
.success {
background-color: var(--successColor);
}
.purple {
background-color: var(--purple);
}
.warning {
background-color: var(--warningColor);
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
}
}
.info {
background-color: var(--infoColor);
}
.queue {
background-color: var(--queueColor);
}
.small {
height: $progressBarSmallHeight;

View File

@@ -38,7 +38,7 @@ function ProgressBar(props) {
{
showText && width ?
<div
className={styles.backTextContainer}
className={classNames(styles.backTextContainer, styles[kind])}
style={{ width: actualWidth }}
>
<div className={styles.backText}>
@@ -67,7 +67,7 @@ function ProgressBar(props) {
{
showText ?
<div
className={styles.frontTextContainer}
className={classNames(styles.frontTextContainer, styles[kind])}
style={{ width: progressPercent }}
>
<div

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -10,7 +11,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import { align, icons, sortDirections } from 'Helpers/Props';
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
import styles from 'Movie/Index/MovieIndex.css';
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
import translate from 'Utilities/String/translate';
@@ -369,9 +370,9 @@ class DiscoverMovie extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMovies')}
</div>
</Alert>
}
{

View File

@@ -39,6 +39,12 @@
flex: 0 0 90px;
}
.popularity {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
flex: 0 0 100px;
}
.lists {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';

View File

@@ -11,6 +11,7 @@ interface CssExports {
'lists': string;
'originalLanguage': string;
'physicalRelease': string;
'popularity': string;
'ratings': string;
'runtime': string;
'sortTitle': string;

View File

@@ -64,6 +64,12 @@
flex: 0 0 90px;
}
.popularity {
composes: cell;
flex: 0 0 100px;
}
.lists {
composes: cell;

View File

@@ -16,6 +16,7 @@ interface CssExports {
'lists': string;
'originalLanguage': string;
'physicalRelease': string;
'popularity': string;
'ratings': string;
'runtime': string;
'sortTitle': string;

View File

@@ -13,6 +13,7 @@ import AddNewDiscoverMovieModal from 'DiscoverMovie/AddNewDiscoverMovieModal';
import ExcludeMovieModal from 'DiscoverMovie/Exclusion/ExcludeMovieModal';
import { icons } from 'Helpers/Props';
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
import MoviePopularityIndex from 'Movie/MoviePopularityIndex';
import formatRuntime from 'Utilities/Date/formatRuntime';
import translate from 'Utilities/String/translate';
import ListMovieStatusCell from './ListMovieStatusCell';
@@ -73,6 +74,7 @@ class DiscoverMovieRow extends Component {
images,
genres,
ratings,
popularity,
certification,
collection,
columns,
@@ -261,6 +263,14 @@ class DiscoverMovieRow extends Component {
);
}
if (name === 'popularity') {
return (
<VirtualTableRowCell key={name} className={styles[name]}>
<MoviePopularityIndex popularity={popularity} />
</VirtualTableRowCell>
);
}
if (name === 'certification') {
return (
<VirtualTableRowCell
@@ -384,6 +394,7 @@ DiscoverMovieRow.propTypes = {
runtime: PropTypes.number,
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
ratings: PropTypes.object.isRequired,
popularity: PropTypes.number.isRequired,
certification: PropTypes.string,
collection: PropTypes.object,
columns: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@@ -61,6 +61,7 @@ import {
faFileInvoice as farFileInvoice,
faFilm as fasFilm,
faFilter as fasFilter,
faFire as fasFire,
faFlag as fasFlag,
faFolderOpen as fasFolderOpen,
faForward as fasForward,
@@ -192,6 +193,7 @@ export const PAUSED = fasPause;
export const PENDING = farClock;
export const PLAY = fasPlay;
export const PROFILE = fasUser;
export const POPULAR = fasFire;
export const POSTER = fasTh;
export const QUEUED = fasCloud;
export const QUICK = fasRocket;

View File

@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
import { useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { LanguageSettingsAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -86,7 +87,9 @@ function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
{isFetching ? <LoadingIndicator /> : null}
{!isFetching && error ? (
<div>{translate('UnableToLoadLanguages')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadLanguages')}
</Alert>
) : null}
{isPopulated && !error ? (

View File

@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
import { createSelector } from 'reselect';
import { Error } from 'App/State/AppSectionState';
import AppState from 'App/State/AppState';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
@@ -130,7 +131,9 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
{isFetching && <LoadingIndicator />}
{!isFetching && error ? (
<div>{translate('UnableToLoadQualities')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</Alert>
) : null}
{isPopulated && !error ? (

View File

@@ -31,6 +31,7 @@ function createMapDispatchToProps(dispatch, props) {
dispatch(
deleteMovie({
id: props.movieId,
collectionTmdbId: this.collection?.tmdbId,
deleteFiles,
addImportExclusion
})

View File

@@ -303,6 +303,7 @@ class MovieDetails extends Component {
selectedTabIndex
} = this.state;
const fanartUrl = getFanartUrl(images);
const marqueeWidth = isSmallScreen ? titleWidth : (titleWidth - 150);
return (
@@ -361,9 +362,11 @@ class MovieDetails extends Component {
<div className={styles.header}>
<div
className={styles.backdrop}
style={{
backgroundImage: `url(${getFanartUrl(images)})`
}}
style={
fanartUrl ?
{ backgroundImage: `url(${fanartUrl})` } :
null
}
>
<div className={styles.backdropOverlay} />
</div>

View File

@@ -0,0 +1,10 @@
.container {
margin-top: 20px;
border: 1px solid var(--borderColor);
border-radius: 4px;
background-color: var(--inputBackgroundColor);
&:last-of-type {
margin-bottom: 0;
}
}

View File

@@ -0,0 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'container': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -1,5 +1,6 @@
import React from 'react';
import MovieHistoryTableContentConnector from './MovieHistoryTableContentConnector';
import styles from './MovieHistoryTable.css';
function MovieHistoryTable(props) {
const {
@@ -7,9 +8,11 @@ function MovieHistoryTable(props) {
} = props;
return (
<MovieHistoryTableContentConnector
{...otherProps}
/>
<div className={styles.container}>
<MovieHistoryTableContentConnector
{...otherProps}
/>
</div>
);
}

View File

@@ -118,6 +118,15 @@ function MovieIndexSortMenu(props: MovieIndexSortMenuProps) {
{translate('TmdbRating')}
</SortMenuItem>
<SortMenuItem
name="popularity"
sortKey={sortKey}
sortDirection={sortDirection}
onPress={onSortSelect}
>
{translate('Popularity')}
</SortMenuItem>
<SortMenuItem
name="path"
sortKey={sortKey}

View File

@@ -10,6 +10,7 @@ import { SelectProvider } from 'App/SelectContext';
import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState';
import MoviesAppState, { MovieIndexAppState } from 'App/State/MoviesAppState';
import { RSS_SYNC } from 'Commands/commandNames';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
@@ -20,7 +21,7 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
import withScrollPosition from 'Components/withScrollPosition';
import { align, icons } from 'Helpers/Props';
import { align, icons, kinds } from 'Helpers/Props';
import SortDirection from 'Helpers/Props/SortDirection';
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import NoMovie from 'Movie/NoMovie';
@@ -337,7 +338,9 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
{isFetching && !isPopulated ? <LoadingIndicator /> : null}
{!isFetching && !!error ? (
<div>{translate('UnableToLoadMovies')}</div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMovies')}
</Alert>
) : null}
{isLoaded ? (

View File

@@ -71,6 +71,9 @@ function MovieIndexOverview(props: MovieIndexOverviewProps) {
isAvailable,
tmdbId,
imdbId,
studio,
sizeOnDisk,
added,
youTubeTrailerId,
} = movie;
@@ -219,6 +222,9 @@ function MovieIndexOverview(props: MovieIndexOverviewProps) {
height={overviewHeight}
monitored={monitored}
qualityProfile={qualityProfile}
studio={studio}
sizeOnDisk={sizeOnDisk}
added={added}
path={path}
sortKey={sortKey}
{...overviewOptions}

View File

@@ -56,7 +56,7 @@ const rows = [
{
name: 'qualityProfileId',
showProp: 'showQualityProfile',
valueProp: 'qualityProfileId',
valueProp: 'qualityProfile',
},
{
name: 'added',

View File

@@ -203,7 +203,7 @@ function EditMoviesModalContent(props: EditMoviesModalContentProps) {
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button onPress={onSavePressWrapper}>
{translate('Apply Changes')}
{translate('ApplyChanges')}
</Button>
</div>
</ModalFooter>

View File

@@ -65,7 +65,7 @@ function OrganizeMoviesModalContent(props: OrganizeMoviesModalContentProps) {
</Alert>
<div className={styles.message}>
{translate('OrganizeConfirm', movieTitles.length)}
{translate('OrganizeConfirm', [movieTitles.length])}
</div>
<ul>

View File

@@ -48,6 +48,7 @@
}
.added,
.popularity,
.runtime {
composes: cell;

View File

@@ -18,6 +18,7 @@ interface CssExports {
'originalTitle': string;
'path': string;
'physicalRelease': string;
'popularity': string;
'qualityProfileId': string;
'rottenTomatoesRating': string;
'runtime': string;

View File

@@ -19,6 +19,7 @@ import DeleteMovieModal from 'Movie/Delete/DeleteMovieModal';
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
import EditMovieModalConnector from 'Movie/Edit/EditMovieModalConnector';
import createMovieIndexItemSelector from 'Movie/Index/createMovieIndexItemSelector';
import MoviePopularityIndex from 'Movie/MoviePopularityIndex';
import MovieTitleLink from 'Movie/MovieTitleLink';
import { executeCommand } from 'Store/Actions/commandActions';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
@@ -69,6 +70,7 @@ function MovieIndexRow(props: MovieIndexRowProps) {
sizeOnDisk,
genres = [],
ratings,
popularity,
certification,
tags = [],
tmdbId,
@@ -362,6 +364,14 @@ function MovieIndexRow(props: MovieIndexRowProps) {
);
}
if (name === 'popularity') {
return (
<VirtualTableRowCell key={name} className={styles[name]}>
<MoviePopularityIndex popularity={popularity} />
</VirtualTableRowCell>
);
}
if (name === 'certification') {
return (
<VirtualTableRowCell key={name} className={styles[name]}>

View File

@@ -41,6 +41,7 @@
}
.added,
.popularity,
.runtime {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';

View File

@@ -15,6 +15,7 @@ interface CssExports {
'originalTitle': string;
'path': string;
'physicalRelease': string;
'popularity': string;
'qualityProfileId': string;
'rottenTomatoesRating': string;
'runtime': string;

View File

@@ -49,6 +49,7 @@ interface Movie extends ModelBase {
sizeOnDisk: number;
genres: string[];
ratings: Ratings;
popularity: number;
certification: string;
tags: number[];
images: Image[];

View File

@@ -0,0 +1,5 @@
.popularityIcon {
margin-right: 2px;
width: 12px !important;
text-align: center;
}

View File

@@ -0,0 +1,7 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'popularityIcon': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,23 @@
import React from 'react';
import Icon from 'Components/Icon';
import Label from 'Components/Label';
import { icons, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './MoviePopularityIndex.css';
interface MoviePopularityIndexProps {
popularity: number;
}
function MoviePopularityIndex(props: MoviePopularityIndexProps) {
const { popularity } = props;
return (
<Label kind={kinds.INVERSE} title={translate('PopularityIndex')}>
<Icon className={styles.popularityIcon} name={icons.POPULAR} size={11} />
{popularity.toFixed()}
</Label>
);
}
export default MoviePopularityIndex;

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } 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';
@@ -109,9 +110,9 @@ class FileEditModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } 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';
@@ -92,9 +93,9 @@ class SelectQualityModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadQualities')}
</div>
</Alert>
}
{

View File

@@ -1,8 +1,10 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody';
import { kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import RootFolderRowConnector from './RootFolderRowConnector';
@@ -44,9 +46,9 @@ function RootFolders(props) {
if (!isFetching && !!error) {
return (
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadRootFolders')}
</div>
</Alert>
);
}

View File

@@ -152,13 +152,7 @@ class CustomFormat extends Component {
isOpen={this.state.isDeleteCustomFormatModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCustomFormat')}
message={
<div>
<div>
{translate('AreYouSureYouWantToDeleteFormat', [name])}
</div>
</div>
}
message={translate('DeleteCustomFormatMessageText', [name])}
confirmLabel={translate('Delete')}
isSpinning={isDeleting}
onConfirm={this.onConfirmDeleteCustomFormat}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import ClipboardButton from 'Components/Link/ClipboardButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -41,9 +42,9 @@ class ExportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } 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';
@@ -11,7 +12,7 @@ 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, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import styles from './ImportCustomFormatModalContent.css';
@@ -95,9 +96,9 @@ class ImportCustomFormatModalContent extends Component {
{
!isFetching && !!error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadCustomFormats')}
</div>
</Alert>
}
{

View File

@@ -78,7 +78,7 @@ class Specification extends Component {
<IconButton
className={styles.cloneButton}
title={translate('CloneFormatTag')}
title={translate('CloneCondition')}
name={icons.CLONE}
onPress={this.onCloneSpecificationPress}
/>
@@ -114,14 +114,8 @@ class Specification extends Component {
<ConfirmModal
isOpen={this.state.isDeleteSpecificationModalOpen}
kind={kinds.DANGER}
title={translate('DeleteCustomFormat')}
message={
<div>
<div>
{translate('AreYouSureYouWantToDeleteFormat', [name])}
</div>
</div>
}
title={translate('DeleteCondition')}
message={translate('DeleteConditionMessageText', [name])}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteSpecification}
onCancel={this.onDeleteSpecificationModalClose}

View File

@@ -86,7 +86,7 @@ class DownloadClientSettings extends Component {
/>
<PageToolbarButton
label="Manage Clients"
label={translate('ManageClients')}
iconName={icons.MANAGE}
onPress={this.onManageDownloadClientsPress}
/>

View File

@@ -3,6 +3,7 @@ import React, { Component } from 'react';
import Card from 'Components/Card';
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 EditDownloadClientModalConnector from './EditDownloadClientModalConnector';
@@ -56,7 +57,9 @@ class DownloadClient extends Component {
id,
name,
enable,
priority
priority,
tags,
tagList
} = this.props;
return (
@@ -94,6 +97,11 @@ class DownloadClient extends Component {
}
</div>
<TagList
tags={tags}
tagList={tagList}
/>
<EditDownloadClientModalConnector
id={id}
isOpen={this.state.isEditDownloadClientModalOpen}
@@ -120,6 +128,8 @@ DownloadClient.propTypes = {
name: PropTypes.string.isRequired,
enable: PropTypes.bool.isRequired,
priority: PropTypes.number.isRequired,
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteDownloadClient: PropTypes.func.isRequired
};

View File

@@ -50,6 +50,7 @@ class DownloadClients extends Component {
const {
items,
onConfirmDeleteDownloadClient,
tagList,
...otherProps
} = this.props;
@@ -71,6 +72,7 @@ class DownloadClients extends Component {
<DownloadClient
key={item.id}
{...item}
tagList={tagList}
onConfirmDeleteDownloadClient={onConfirmDeleteDownloadClient}
/>
);
@@ -109,6 +111,7 @@ DownloadClients.propTypes = {
isFetching: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
onConfirmDeleteDownloadClient: PropTypes.func.isRequired
};

View File

@@ -4,13 +4,20 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { deleteDownloadClient, fetchDownloadClients } from 'Store/Actions/settingsActions';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import createTagsSelector from 'Store/Selectors/createTagsSelector';
import sortByName from 'Utilities/Array/sortByName';
import DownloadClients from './DownloadClients';
function createMapStateToProps() {
return createSelector(
createSortedSectionSelector('settings.downloadClients', sortByName),
(downloadClients) => downloadClients
createTagsSelector(),
(downloadClients, tagList) => {
return {
...downloadClients,
tagList
};
}
);
}

View File

@@ -51,6 +51,7 @@ class EditDownloadClientModalContent extends Component {
removeCompletedDownloads,
removeFailedDownloads,
fields,
tags,
message
} = item;
@@ -140,6 +141,18 @@ class EditDownloadClientModalContent extends Component {
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
name="tags"
helpText={translate('DownloadClientTagHelpText')}
{...tags}
onChange={onInputChange}
/>
</FormGroup>
<FieldSet
size={sizes.SMALL}
legend={translate('CompletedDownloadHandling')}

View File

@@ -27,9 +27,9 @@ interface ManageDownloadClientsEditModalContentProps {
const NO_CHANGE = 'noChange';
const enableOptions = [
{ key: NO_CHANGE, value: 'No Change', disabled: true },
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabled', value: 'Disabled' },
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
{ key: 'enabled', value: translate('Enabled') },
{ key: 'disabled', value: translate('Disabled') },
];
function ManageDownloadClientsEditModalContent(
@@ -97,7 +97,9 @@ function ManageDownloadClientsEditModalContent(
setRemoveFailedDownloads(value);
break;
default:
console.warn('EditDownloadClientsModalContent Unknown Input');
console.warn(
`EditDownloadClientsModalContent Unknown Input: '${name}'`
);
}
},
[]
@@ -162,15 +164,13 @@ function ManageDownloadClientsEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('{count} download clients selected', {
count: selectedCount,
})}
{translate('CountDownloadClientsSelected', [selectedCount])}
</div>
<div>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button onPress={save}>{translate('Apply Changes')}</Button>
<Button onPress={save}>{translate('ApplyChanges')}</Button>
</div>
</ModalFooter>
</ModalContent>

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { DownloadClientAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -20,9 +21,11 @@ import {
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import { SelectStateInputProps } from 'typings/props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import ManageDownloadClientsEditModal from './Edit/ManageDownloadClientsEditModal';
import ManageDownloadClientsModalRow from './ManageDownloadClientsModalRow';
import TagsModal from './Tags/TagsModal';
import styles from './ManageDownloadClientsModalContent.css';
// TODO: This feels janky to do, but not sure of a better way currently
@@ -33,37 +36,43 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [
{
name: 'name',
label: 'Name',
label: translate('Name'),
isSortable: true,
isVisible: true,
},
{
name: 'implementation',
label: 'Implementation',
label: translate('Implementation'),
isSortable: true,
isVisible: true,
},
{
name: 'enable',
label: 'Enabled',
label: translate('Enabled'),
isSortable: true,
isVisible: true,
},
{
name: 'priority',
label: 'Priority',
label: translate('Priority'),
isSortable: true,
isVisible: true,
},
{
name: 'removeCompletedDownloads',
label: 'Remove Completed',
label: translate('RemoveCompleted'),
isSortable: true,
isVisible: true,
},
{
name: 'removeFailedDownloads',
label: 'Remove Failed',
label: translate('RemoveFailed'),
isSortable: true,
isVisible: true,
},
{
name: 'tags',
label: 'Tags',
isSortable: true,
isVisible: true,
},
@@ -92,6 +101,8 @@ function ManageDownloadClientsModalContent(
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
const [isTagsModalOpen, setIsTagsModalOpen] = useState(false);
const [isSavingTags, setIsSavingTags] = useState(false);
const [selectState, setSelectState] = useSelectState();
@@ -138,6 +149,30 @@ function ManageDownloadClientsModalContent(
[selectedIds, dispatch]
);
const onTagsPress = useCallback(() => {
setIsTagsModalOpen(true);
}, [setIsTagsModalOpen]);
const onTagsModalClose = useCallback(() => {
setIsTagsModalOpen(false);
}, [setIsTagsModalOpen]);
const onApplyTagsPress = useCallback(
(tags: number[], applyTags: string) => {
setIsSavingTags(true);
setIsTagsModalOpen(false);
dispatch(
bulkEditDownloadClients({
ids: selectedIds,
tags,
applyTags,
})
);
},
[selectedIds, dispatch]
);
const onSelectAllChange = useCallback(
({ value }: SelectStateInputProps) => {
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
@@ -158,17 +193,24 @@ function ManageDownloadClientsModalContent(
[items, setSelectState]
);
const errorMessage = getErrorMessage(error, 'Unable to load import lists.');
const errorMessage = getErrorMessage(
error,
'Unable to load download clients.'
);
const anySelected = selectedCount > 0;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>Manage Import Lists</ModalHeader>
<ModalHeader>{translate('ManageDownloadClients')}</ModalHeader>
<ModalBody>
{isFetching ? <LoadingIndicator /> : null}
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
<Alert kind={kinds.INFO}>{translate('NoDownloadClientsFound')}</Alert>
)}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table
columns={COLUMNS}
@@ -203,7 +245,7 @@ function ManageDownloadClientsModalContent(
isDisabled={!anySelected}
onPress={onDeletePress}
>
Delete
{translate('Delete')}
</SpinnerButton>
<SpinnerButton
@@ -211,11 +253,19 @@ function ManageDownloadClientsModalContent(
isDisabled={!anySelected}
onPress={onEditPress}
>
Edit
{translate('Edit')}
</SpinnerButton>
<SpinnerButton
isSpinning={isSaving && isSavingTags}
isDisabled={!anySelected}
onPress={onTagsPress}
>
{translate('SetTags')}
</SpinnerButton>
</div>
<Button onPress={onModalClose}>Close</Button>
<Button onPress={onModalClose}>{translate('Close')}</Button>
</ModalFooter>
<ManageDownloadClientsEditModal
@@ -225,12 +275,21 @@ function ManageDownloadClientsModalContent(
downloadClientIds={selectedIds}
/>
<TagsModal
isOpen={isTagsModalOpen}
ids={selectedIds}
onApplyTagsPress={onApplyTagsPress}
onModalClose={onTagsModalClose}
/>
<ConfirmModal
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title="Delete Download Clients(s)"
message={`Are you sure you want to delete ${selectedIds.length} download clients(s)?`}
confirmLabel="Delete"
title={translate('DeleteSelectedDownloadClients')}
message={translate('DeleteSelectedDownloadClientsMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}
/>

View File

@@ -1,9 +1,13 @@
import React, { useCallback } from 'react';
import Label from 'Components/Label';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import Column from 'Components/Table/Column';
import TableRow from 'Components/Table/TableRow';
import TagListConnector from 'Components/TagListConnector';
import { kinds } from 'Helpers/Props';
import { SelectStateInputProps } from 'typings/props';
import translate from 'Utilities/String/translate';
import styles from './ManageDownloadClientsModalRow.css';
interface ManageDownloadClientsModalRowProps {
@@ -14,6 +18,7 @@ interface ManageDownloadClientsModalRowProps {
removeCompletedDownloads: boolean;
removeFailedDownloads: boolean;
implementation: string;
tags: number[];
columns: Column[];
isSelected?: boolean;
onSelectedChange(result: SelectStateInputProps): void;
@@ -31,6 +36,7 @@ function ManageDownloadClientsModalRow(
removeCompletedDownloads,
removeFailedDownloads,
implementation,
tags,
onSelectedChange,
} = props;
@@ -58,17 +64,23 @@ function ManageDownloadClientsModalRow(
</TableRowCell>
<TableRowCell className={styles.enable}>
{enable ? 'Yes' : 'No'}
<Label kind={enable ? kinds.SUCCESS : kinds.DISABLED} outline={!enable}>
{enable ? translate('Yes') : translate('No')}
</Label>
</TableRowCell>
<TableRowCell className={styles.priority}>{priority}</TableRowCell>
<TableRowCell className={styles.removeCompletedDownloads}>
{removeCompletedDownloads ? 'Yes' : 'No'}
{removeCompletedDownloads ? translate('Yes') : translate('No')}
</TableRowCell>
<TableRowCell className={styles.removeFailedDownloads}>
{removeFailedDownloads ? 'Yes' : 'No'}
{removeFailedDownloads ? translate('Yes') : translate('No')}
</TableRowCell>
<TableRowCell className={styles.tags}>
<TagListConnector tags={tags} />
</TableRowCell>
</TableRow>
);

View File

@@ -0,0 +1,22 @@
import React from 'react';
import Modal from 'Components/Modal/Modal';
import TagsModalContent from './TagsModalContent';
interface TagsModalProps {
isOpen: boolean;
ids: number[];
onApplyTagsPress: (tags: number[], applyTags: string) => void;
onModalClose: () => void;
}
function TagsModal(props: TagsModalProps) {
const { isOpen, onModalClose, ...otherProps } = props;
return (
<Modal isOpen={isOpen} onModalClose={onModalClose}>
<TagsModalContent {...otherProps} onModalClose={onModalClose} />
</Modal>
);
}
export default TagsModal;

View File

@@ -0,0 +1,12 @@
.renameIcon {
margin-left: 5px;
}
.message {
margin-top: 20px;
margin-bottom: 10px;
}
.result {
padding-top: 4px;
}

View File

@@ -0,0 +1,9 @@
// This file is automatically generated.
// Please do not change this file!
interface CssExports {
'message': string;
'renameIcon': string;
'result': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -0,0 +1,185 @@
import { uniq } from 'lodash';
import React, { useCallback, useMemo, useState } from 'react';
import { useSelector } from 'react-redux';
import AppState from 'App/State/AppState';
import { DownloadClientAppState } from 'App/State/SettingsAppState';
import { Tag } from 'App/State/TagsAppState';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import Label from 'Components/Label';
import Button from 'Components/Link/Button';
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 createTagsSelector from 'Store/Selectors/createTagsSelector';
import DownloadClient from 'typings/DownloadClient';
import translate from 'Utilities/String/translate';
import styles from './TagsModalContent.css';
interface TagsModalContentProps {
ids: number[];
onApplyTagsPress: (tags: number[], applyTags: string) => void;
onModalClose: () => void;
}
function TagsModalContent(props: TagsModalContentProps) {
const { ids, onModalClose, onApplyTagsPress } = props;
const allDownloadClients: DownloadClientAppState = useSelector(
(state: AppState) => state.settings.downloadClients
);
const tagList: Tag[] = useSelector(createTagsSelector());
const [tags, setTags] = useState<number[]>([]);
const [applyTags, setApplyTags] = useState('add');
const downloadClientsTags = useMemo(() => {
const tags = ids.reduce((acc: number[], id) => {
const s = allDownloadClients.items.find(
(s: DownloadClient) => s.id === id
);
if (s) {
acc.push(...s.tags);
}
return acc;
}, []);
return uniq(tags);
}, [ids, allDownloadClients]);
const onTagsChange = useCallback(
({ value }: { value: number[] }) => {
setTags(value);
},
[setTags]
);
const onApplyTagsChange = useCallback(
({ value }: { value: string }) => {
setApplyTags(value);
},
[setApplyTags]
);
const onApplyPress = useCallback(() => {
onApplyTagsPress(tags, applyTags);
}, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [
{ key: 'add', value: translate('Add') },
{ key: 'remove', value: translate('Remove') },
{ key: 'replace', value: translate('Replace') },
];
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>{translate('Tags')}</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
name="tags"
value={tags}
onChange={onTagsChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('ApplyTags')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
name="applyTags"
value={applyTags}
values={applyTagsOptions}
helpTexts={[
translate('ApplyTagsHelpTextHowToApplyDownloadClients'),
translate('ApplyTagsHelpTextAdd'),
translate('ApplyTagsHelpTextRemove'),
translate('ApplyTagsHelpTextReplace'),
]}
onChange={onApplyTagsChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>{translate('Result')}</FormLabel>
<div className={styles.result}>
{downloadClientsTags.map((id) => {
const tag = tagList.find((t) => t.id === id);
if (!tag) {
return null;
}
const removeTag =
(applyTags === 'remove' && tags.indexOf(id) > -1) ||
(applyTags === 'replace' && tags.indexOf(id) === -1);
return (
<Label
key={tag.id}
title={
removeTag
? translate('RemovingTag')
: translate('ExistingTag')
}
kind={removeTag ? kinds.INVERSE : kinds.INFO}
size={sizes.LARGE}
>
{tag.label}
</Label>
);
})}
{(applyTags === 'add' || applyTags === 'replace') &&
tags.map((id) => {
const tag = tagList.find((t) => t.id === id);
if (!tag) {
return null;
}
if (downloadClientsTags.indexOf(id) > -1) {
return null;
}
return (
<Label
key={tag.id}
title={translate('AddingTag')}
kind={kinds.SUCCESS}
size={sizes.LARGE}
>
{tag.label}
</Label>
);
})}
</div>
</FormGroup>
</Form>
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.PRIMARY} onPress={onApplyPress}>
{translate('Apply')}
</Button>
</ModalFooter>
</ModalContent>
);
}
export default TagsModalContent;

View File

@@ -29,9 +29,9 @@ function DownloadClientOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadDownloadClientOptions')}
</div>
</Alert>
}
{

View File

@@ -88,8 +88,8 @@ class RemotePathMapping extends Component {
<ConfirmModal
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('AreYouSureYouWantToDeleteThisRemotePathMapping')}
title={translate('DeleteRemotePathMapping')}
message={translate('DeleteRemotePathMappingMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteRemotePathMapping}
onCancel={this.onDeleteRemotePathMappingModalClose}

View File

@@ -1,6 +1,7 @@
import _ from 'lodash';
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import Form from 'Components/Form/Form';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import ConfirmModal from 'Components/Modal/ConfirmModal';
@@ -123,9 +124,9 @@ class GeneralSettings extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadGeneralSettings')}
</div>
</Alert>
}
{

View File

@@ -168,7 +168,7 @@ class SecuritySettings extends Component {
isOpen={this.state.isConfirmApiKeyResetModalOpen}
kind={kinds.DANGER}
title={translate('ResetAPIKey')}
message={translate('AreYouSureYouWantToResetYourAPIKey')}
message={translate('ResetAPIKeyMessageText')}
confirmLabel={translate('Reset')}
onConfirm={this.onConfirmResetApiKey}
onCancel={this.onCloseResetApiKeyModal}

View File

@@ -89,7 +89,7 @@ class ImportListExclusion extends Component {
isOpen={this.state.isDeleteImportExclusionModalOpen}
kind={kinds.DANGER}
title={translate('DeleteImportListExclusion')}
message={translate('AreYouSureYouWantToDeleteThisImportListExclusion')}
message={translate('DeleteImportListExclusionMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteImportExclusion}
onCancel={this.onDeleteImportExclusionModalClose}

View File

@@ -86,7 +86,7 @@ class ImportListSettings extends Component {
/>
<PageToolbarButton
label="Manage Lists"
label={translate('ManageLists')}
iconName={icons.MANAGE}
onPress={this.onManageImportListsPress}
/>

View File

@@ -3,3 +3,9 @@
margin-right: auto;
}
.message {
composes: alert from '~Components/Alert.css';
margin-bottom: 30px;
}

View File

@@ -2,6 +2,7 @@
// Please do not change this file!
interface CssExports {
'deleteButton': string;
'message': string;
}
export const cssExports: CssExports;
export default cssExports;

View File

@@ -14,6 +14,7 @@ import ModalContent from 'Components/Modal/ModalContent';
import ModalFooter from 'Components/Modal/ModalFooter';
import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds } from 'Helpers/Props';
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
import translate from 'Utilities/String/translate';
import styles from './EditImportListModalContent.css';
@@ -42,6 +43,7 @@ function EditImportListModalContent(props) {
name,
enabled,
enableAuto,
minRefreshInterval,
monitor,
minimumAvailability,
qualityProfileId,
@@ -85,6 +87,14 @@ function EditImportListModalContent(props) {
{message.value.message}
</Alert>
}
<Alert
kind={kinds.INFO}
className={styles.message}
>
{translate('ListWillRefreshEveryInterp', [formatShortTimeSpan(minRefreshInterval.value)])}
</Alert>
<FormGroup>
<FormLabel>{translate('Name')}</FormLabel>

View File

@@ -4,6 +4,7 @@ import Card from 'Components/Card';
import Label from 'Components/Label';
import ConfirmModal from 'Components/Modal/ConfirmModal';
import { kinds } from 'Helpers/Props';
import formatShortTimeSpan from 'Utilities/Date/formatShortTimeSpan';
import translate from 'Utilities/String/translate';
import EditImportListModalConnector from './EditImportListModalConnector';
import styles from './ImportList.css';
@@ -56,7 +57,8 @@ class ImportList extends Component {
id,
name,
enabled,
enableAuto
enableAuto,
minRefreshInterval
} = this.props;
return (
@@ -96,6 +98,12 @@ class ImportList extends Component {
}
</div>
<div className={styles.enabled}>
<Label kind={kinds.INFO} title='List Refresh Interval'>
{`${translate('Refresh')}: ${formatShortTimeSpan(minRefreshInterval)}`}
</Label>
</div>
<EditImportListModalConnector
id={id}
isOpen={this.state.isEditImportListModalOpen}
@@ -122,6 +130,7 @@ ImportList.propTypes = {
name: PropTypes.string.isRequired,
enabled: PropTypes.bool.isRequired,
enableAuto: PropTypes.bool.isRequired,
minRefreshInterval: PropTypes.string.isRequired,
onConfirmDeleteImportList: PropTypes.func.isRequired
};

View File

@@ -26,9 +26,9 @@ interface ManageImportListsEditModalContentProps {
const NO_CHANGE = 'noChange';
const autoAddOptions = [
{ key: NO_CHANGE, value: 'No Change', disabled: true },
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabled', value: 'Disabled' },
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
{ key: 'enabled', value: translate('Enabled') },
{ key: 'disabled', value: translate('Disabled') },
];
function ManageImportListsEditModalContent(
@@ -36,7 +36,7 @@ function ManageImportListsEditModalContent(
) {
const { importListIds, onSavePress, onModalClose } = props;
const [enableAuto, setenableAuto] = useState(NO_CHANGE);
const [enableAuto, setEnableAuto] = useState(NO_CHANGE);
const [qualityProfileId, setQualityProfileId] = useState<string | number>(
NO_CHANGE
);
@@ -72,7 +72,7 @@ function ManageImportListsEditModalContent(
({ name, value }: { name: string; value: string }) => {
switch (name) {
case 'enableAuto':
setenableAuto(value);
setEnableAuto(value);
break;
case 'qualityProfileId':
setQualityProfileId(value);
@@ -81,7 +81,7 @@ function ManageImportListsEditModalContent(
setRootFolderPath(value);
break;
default:
console.warn('EditImportListModalContent Unknown Input');
console.warn(`EditImportListModalContent Unknown Input: '${name}'`);
}
},
[]
@@ -136,7 +136,7 @@ function ManageImportListsEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('{count} import lists selected', { count: selectedCount })}
{translate('CountImportListsSelected', [selectedCount])}
</div>
<div>

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { ImportListAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -20,6 +21,7 @@ import {
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import { SelectStateInputProps } from 'typings/props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import ManageImportListsEditModal from './Edit/ManageImportListsEditModal';
import ManageImportListsModalRow from './ManageImportListsModalRow';
@@ -34,37 +36,37 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [
{
name: 'name',
label: 'Name',
label: translate('Name'),
isSortable: true,
isVisible: true,
},
{
name: 'implementation',
label: 'Implementation',
label: translate('Implementation'),
isSortable: true,
isVisible: true,
},
{
name: 'qualityProfileId',
label: 'Quality Profile',
label: translate('QualityProfile'),
isSortable: true,
isVisible: true,
},
{
name: 'rootFolderPath',
label: 'Root Folder',
label: translate('RootFolder'),
isSortable: true,
isVisible: true,
},
{
name: 'enableAuto',
label: 'Auto Add',
label: translate('AutomaticAdd'),
isSortable: true,
isVisible: true,
},
{
name: 'tags',
label: 'Tags',
label: translate('Tags'),
isSortable: true,
isVisible: true,
},
@@ -190,12 +192,16 @@ function ManageImportListsModalContent(
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>Manage Import Lists</ModalHeader>
<ModalHeader>{translate('ManageImportLists')}</ModalHeader>
<ModalBody>
{isFetching ? <LoadingIndicator /> : null}
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
<Alert kind={kinds.INFO}>{translate('NoImportListsFound')}</Alert>
)}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table
columns={COLUMNS}
@@ -230,7 +236,7 @@ function ManageImportListsModalContent(
isDisabled={!anySelected}
onPress={onDeletePress}
>
Delete
{translate('Delete')}
</SpinnerButton>
<SpinnerButton
@@ -238,7 +244,7 @@ function ManageImportListsModalContent(
isDisabled={!anySelected}
onPress={onEditPress}
>
Edit
{translate('Edit')}
</SpinnerButton>
<SpinnerButton
@@ -246,11 +252,11 @@ function ManageImportListsModalContent(
isDisabled={!anySelected}
onPress={onTagsPress}
>
Set Tags
{translate('SetTags')}
</SpinnerButton>
</div>
<Button onPress={onModalClose}>Close</Button>
<Button onPress={onModalClose}>{translate('Close')}</Button>
</ModalFooter>
<ManageImportListsEditModal
@@ -270,9 +276,11 @@ function ManageImportListsModalContent(
<ConfirmModal
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title="Delete Import List(s)"
message={`Are you sure you want to delete ${selectedIds.length} import list(s)?`}
confirmLabel="Delete"
title={translate('DeleteSelectedImportLists')}
message={translate('DeleteSelectedImportListsMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}
/>

View File

@@ -17,6 +17,7 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import createTagsSelector from 'Store/Selectors/createTagsSelector';
import ImportList from 'typings/ImportList';
import translate from 'Utilities/String/translate';
import styles from './TagsModalContent.css';
interface TagsModalContentProps {
@@ -36,7 +37,7 @@ function TagsModalContent(props: TagsModalContentProps) {
const [tags, setTags] = useState<number[]>([]);
const [applyTags, setApplyTags] = useState('add');
const seriesTags = useMemo(() => {
const importListsTags = useMemo(() => {
const tags = ids.reduce((acc: number[], id) => {
const s = allImportLists.items.find((s: ImportList) => s.id === id);
@@ -69,19 +70,19 @@ function TagsModalContent(props: TagsModalContentProps) {
}, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [
{ key: 'add', value: 'Add' },
{ key: 'remove', value: 'Remove' },
{ key: 'replace', value: 'Replace' },
{ key: 'add', value: translate('Add') },
{ key: 'remove', value: translate('Remove') },
{ key: 'replace', value: translate('Replace') },
];
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>Tags</ModalHeader>
<ModalHeader>{translate('Tags')}</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
@@ -92,7 +93,7 @@ function TagsModalContent(props: TagsModalContentProps) {
</FormGroup>
<FormGroup>
<FormLabel>Apply Tags</FormLabel>
<FormLabel>{translate('ApplyTags')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@@ -100,20 +101,20 @@ function TagsModalContent(props: TagsModalContentProps) {
value={applyTags}
values={applyTagsOptions}
helpTexts={[
'How to apply tags to the selected list',
'Add: Add the tags the existing list of tags',
'Remove: Remove the entered tags',
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)',
translate('ApplyTagsHelpTextHowToApplyImportLists'),
translate('ApplyTagsHelpTextAdd'),
translate('ApplyTagsHelpTextRemove'),
translate('ApplyTagsHelpTextReplace'),
]}
onChange={onApplyTagsChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Result</FormLabel>
<FormLabel>{translate('Result')}</FormLabel>
<div className={styles.result}>
{seriesTags.map((id) => {
{importListsTags.map((id) => {
const tag = tagList.find((t) => t.id === id);
if (!tag) {
@@ -127,7 +128,11 @@ function TagsModalContent(props: TagsModalContentProps) {
return (
<Label
key={tag.id}
title={removeTag ? 'Removing tag' : 'Existing tag'}
title={
removeTag
? translate('RemovingTag')
: translate('ExistingTag')
}
kind={removeTag ? kinds.INVERSE : kinds.INFO}
size={sizes.LARGE}
>
@@ -144,14 +149,14 @@ function TagsModalContent(props: TagsModalContentProps) {
return null;
}
if (seriesTags.indexOf(id) > -1) {
if (importListsTags.indexOf(id) > -1) {
return null;
}
return (
<Label
key={tag.id}
title={'Adding tag'}
title={translate('AddingTag')}
kind={kinds.SUCCESS}
size={sizes.LARGE}
>
@@ -165,10 +170,10 @@ function TagsModalContent(props: TagsModalContentProps) {
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.PRIMARY} onPress={onApplyPress}>
Apply
{translate('Apply')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function ImportListOptions(props) {
@@ -37,31 +38,14 @@ function ImportListOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadListOptions')}
</div>
</Alert>
}
{
hasSettings && !isFetching && !error &&
<Form>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}
>
<FormLabel>{translate('ListUpdateInterval')}</FormLabel>
<FormInputGroup
type={inputTypes.NUMBER}
name="importListSyncInterval"
min={6}
unit="hours"
helpText={translate('ImportListSyncIntervalHelpText')}
onChange={onInputChange}
{...settings.importListSyncInterval}
/>
</FormGroup>
<FormGroup
advancedSettings={advancedSettings}
isAdvanced={true}

View File

@@ -86,7 +86,7 @@ class IndexerSettings extends Component {
/>
<PageToolbarButton
label="Manage Indexers"
label={translate('ManageIndexers')}
iconName={icons.MANAGE}
onPress={this.onManageIndexersPress}
/>

View File

@@ -27,9 +27,9 @@ interface ManageIndexersEditModalContentProps {
const NO_CHANGE = 'noChange';
const enableOptions = [
{ key: NO_CHANGE, value: 'No Change', disabled: true },
{ key: 'enabled', value: 'Enabled' },
{ key: 'disabled', value: 'Disabled' },
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
{ key: 'enabled', value: translate('Enabled') },
{ key: 'disabled', value: translate('Disabled') },
];
function ManageIndexersEditModalContent(
@@ -97,7 +97,7 @@ function ManageIndexersEditModalContent(
setPriority(value);
break;
default:
console.warn('EditIndexersModalContent Unknown Input');
console.warn(`EditIndexersModalContent Unknown Input: '${name}'`);
}
},
[]
@@ -111,7 +111,7 @@ function ManageIndexersEditModalContent(
<ModalBody>
<FormGroup>
<FormLabel>{translate('EnableRss')}</FormLabel>
<FormLabel>{translate('EnableRSS')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@@ -162,13 +162,13 @@ function ManageIndexersEditModalContent(
<ModalFooter className={styles.modalFooter}>
<div className={styles.selected}>
{translate('{count} indexers selected', { count: selectedCount })}
{translate('CountIndexersSelected', [selectedCount])}
</div>
<div>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button onPress={save}>{translate('Apply Changes')}</Button>
<Button onPress={save}>{translate('ApplyChanges')}</Button>
</div>
</ModalFooter>
</ModalContent>

View File

@@ -1,6 +1,7 @@
import React, { useCallback, useMemo, useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { IndexerAppState } from 'App/State/SettingsAppState';
import Alert from 'Components/Alert';
import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
@@ -20,6 +21,7 @@ import {
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
import { SelectStateInputProps } from 'typings/props';
import getErrorMessage from 'Utilities/Object/getErrorMessage';
import translate from 'Utilities/String/translate';
import getSelectedIds from 'Utilities/Table/getSelectedIds';
import ManageIndexersEditModal from './Edit/ManageIndexersEditModal';
import ManageIndexersModalRow from './ManageIndexersModalRow';
@@ -34,43 +36,43 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [
{
name: 'name',
label: 'Name',
label: translate('Name'),
isSortable: true,
isVisible: true,
},
{
name: 'implementation',
label: 'Implementation',
label: translate('Implementation'),
isSortable: true,
isVisible: true,
},
{
name: 'enableRss',
label: 'Enable RSS',
label: translate('EnableRSS'),
isSortable: true,
isVisible: true,
},
{
name: 'enableAutomaticSearch',
label: 'Enable Automatic Search',
label: translate('EnableAutomaticSearch'),
isSortable: true,
isVisible: true,
},
{
name: 'enableInteractiveSearch',
label: 'Enable Interactive Search',
label: translate('EnableInteractiveSearch'),
isSortable: true,
isVisible: true,
},
{
name: 'priority',
label: 'Priority',
label: translate('Priority'),
isSortable: true,
isVisible: true,
},
{
name: 'tags',
label: 'Tags',
label: translate('Tags'),
isSortable: true,
isVisible: true,
},
@@ -189,17 +191,21 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
[items, setSelectState]
);
const errorMessage = getErrorMessage(error, 'Unable to load import lists.');
const errorMessage = getErrorMessage(error, 'Unable to load indexers.');
const anySelected = selectedCount > 0;
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>Manage Import Lists</ModalHeader>
<ModalHeader>{translate('ManageIndexers')}</ModalHeader>
<ModalBody>
{isFetching ? <LoadingIndicator /> : null}
{error ? <div>{errorMessage}</div> : null}
{isPopulated && !error && !items.length && (
<Alert kind={kinds.INFO}>{translate('NoIndexersFound')}</Alert>
)}
{isPopulated && !!items.length && !isFetching && !isFetching ? (
<Table
columns={COLUMNS}
@@ -234,7 +240,7 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
isDisabled={!anySelected}
onPress={onDeletePress}
>
Delete
{translate('Delete')}
</SpinnerButton>
<SpinnerButton
@@ -242,7 +248,7 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
isDisabled={!anySelected}
onPress={onEditPress}
>
Edit
{translate('Edit')}
</SpinnerButton>
<SpinnerButton
@@ -250,11 +256,11 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
isDisabled={!anySelected}
onPress={onTagsPress}
>
Set Tags
{translate('SetTags')}
</SpinnerButton>
</div>
<Button onPress={onModalClose}>Close</Button>
<Button onPress={onModalClose}>{translate('Close')}</Button>
</ModalFooter>
<ManageIndexersEditModal
@@ -274,9 +280,11 @@ function ManageIndexersModalContent(props: ManageIndexersModalContentProps) {
<ConfirmModal
isOpen={isDeleteModalOpen}
kind={kinds.DANGER}
title="Delete Import List(s)"
message={`Are you sure you want to delete ${selectedIds.length} import list(s)?`}
confirmLabel="Delete"
title={translate('DeleteSelectedIndexers')}
message={translate('DeleteSelectedIndexersMessageText', [
selectedIds.length,
])}
confirmLabel={translate('Delete')}
onConfirm={onConfirmDelete}
onCancel={onDeleteModalClose}
/>

View File

@@ -1,10 +1,13 @@
import React, { useCallback } from 'react';
import Label from 'Components/Label';
import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import Column from 'Components/Table/Column';
import TableRow from 'Components/Table/TableRow';
import TagListConnector from 'Components/TagListConnector';
import { kinds } from 'Helpers/Props';
import { SelectStateInputProps } from 'typings/props';
import translate from 'Utilities/String/translate';
import styles from './ManageIndexersModalRow.css';
interface ManageIndexersModalRowProps {
@@ -59,15 +62,30 @@ function ManageIndexersModalRow(props: ManageIndexersModalRowProps) {
</TableRowCell>
<TableRowCell className={styles.enableRss}>
{enableRss ? 'Yes' : 'No'}
<Label
kind={enableRss ? kinds.SUCCESS : kinds.DISABLED}
outline={!enableRss}
>
{enableRss ? translate('Yes') : translate('No')}
</Label>
</TableRowCell>
<TableRowCell className={styles.enableAutomaticSearch}>
{enableAutomaticSearch ? 'Yes' : 'No'}
<Label
kind={enableAutomaticSearch ? kinds.SUCCESS : kinds.DISABLED}
outline={!enableAutomaticSearch}
>
{enableAutomaticSearch ? translate('Yes') : translate('No')}
</Label>
</TableRowCell>
<TableRowCell className={styles.enableInteractiveSearch}>
{enableInteractiveSearch ? 'Yes' : 'No'}
<Label
kind={enableInteractiveSearch ? kinds.SUCCESS : kinds.DISABLED}
outline={!enableInteractiveSearch}
>
{enableInteractiveSearch ? translate('Yes') : translate('No')}
</Label>
</TableRowCell>
<TableRowCell className={styles.priority}>{priority}</TableRowCell>

View File

@@ -17,6 +17,7 @@ import ModalHeader from 'Components/Modal/ModalHeader';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import createTagsSelector from 'Store/Selectors/createTagsSelector';
import Indexer from 'typings/Indexer';
import translate from 'Utilities/String/translate';
import styles from './TagsModalContent.css';
interface TagsModalContentProps {
@@ -36,7 +37,7 @@ function TagsModalContent(props: TagsModalContentProps) {
const [tags, setTags] = useState<number[]>([]);
const [applyTags, setApplyTags] = useState('add');
const seriesTags = useMemo(() => {
const indexersTags = useMemo(() => {
const tags = ids.reduce((acc: number[], id) => {
const s = allIndexers.items.find((s: Indexer) => s.id === id);
@@ -69,19 +70,19 @@ function TagsModalContent(props: TagsModalContentProps) {
}, [tags, applyTags, onApplyTagsPress]);
const applyTagsOptions = [
{ key: 'add', value: 'Add' },
{ key: 'remove', value: 'Remove' },
{ key: 'replace', value: 'Replace' },
{ key: 'add', value: translate('Add') },
{ key: 'remove', value: translate('Remove') },
{ key: 'replace', value: translate('Replace') },
];
return (
<ModalContent onModalClose={onModalClose}>
<ModalHeader>Tags</ModalHeader>
<ModalHeader>{translate('Tags')}</ModalHeader>
<ModalBody>
<Form>
<FormGroup>
<FormLabel>Tags</FormLabel>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
@@ -92,7 +93,7 @@ function TagsModalContent(props: TagsModalContentProps) {
</FormGroup>
<FormGroup>
<FormLabel>Apply Tags</FormLabel>
<FormLabel>{translate('ApplyTags')}</FormLabel>
<FormInputGroup
type={inputTypes.SELECT}
@@ -100,20 +101,20 @@ function TagsModalContent(props: TagsModalContentProps) {
value={applyTags}
values={applyTagsOptions}
helpTexts={[
'How to apply tags to the selected indexer(s)',
'Add: Add the tags the existing list of tags',
'Remove: Remove the entered tags',
'Replace: Replace the tags with the entered tags (enter no tags to clear all tags)',
translate('ApplyTagsHelpTextHowToApplyIndexers'),
translate('ApplyTagsHelpTextAdd'),
translate('ApplyTagsHelpTextRemove'),
translate('ApplyTagsHelpTextReplace'),
]}
onChange={onApplyTagsChange}
/>
</FormGroup>
<FormGroup>
<FormLabel>Result</FormLabel>
<FormLabel>{translate('Result')}</FormLabel>
<div className={styles.result}>
{seriesTags.map((id) => {
{indexersTags.map((id) => {
const tag = tagList.find((t) => t.id === id);
if (!tag) {
@@ -127,7 +128,11 @@ function TagsModalContent(props: TagsModalContentProps) {
return (
<Label
key={tag.id}
title={removeTag ? 'Removing tag' : 'Existing tag'}
title={
removeTag
? translate('RemovingTag')
: translate('ExistingTag')
}
kind={removeTag ? kinds.INVERSE : kinds.INFO}
size={sizes.LARGE}
>
@@ -144,14 +149,14 @@ function TagsModalContent(props: TagsModalContentProps) {
return null;
}
if (seriesTags.indexOf(id) > -1) {
if (indexersTags.indexOf(id) > -1) {
return null;
}
return (
<Label
key={tag.id}
title={'Adding tag'}
title={translate('AddingTag')}
kind={kinds.SUCCESS}
size={sizes.LARGE}
>
@@ -165,10 +170,10 @@ function TagsModalContent(props: TagsModalContentProps) {
</ModalBody>
<ModalFooter>
<Button onPress={onModalClose}>Cancel</Button>
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
<Button kind={kinds.PRIMARY} onPress={onApplyPress}>
Apply
{translate('Apply')}
</Button>
</ModalFooter>
</ModalContent>

View File

@@ -1,12 +1,13 @@
import PropTypes from 'prop-types';
import React from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
function IndexerOptions(props) {
@@ -28,9 +29,9 @@ function IndexerOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
</div>
</Alert>
}
{

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -8,7 +9,7 @@ import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import PageContent from 'Components/Page/PageContent';
import PageContentBody from 'Components/Page/PageContentBody';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import RootFoldersConnector from 'RootFolder/RootFoldersConnector';
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
import translate from 'Utilities/String/translate';
@@ -72,9 +73,9 @@ class MediaManagement extends Component {
{
!isFetching && error ?
<FieldSet legend={translate('NamingSettings')}>
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadMediaManagementSettings')}
</div>
</Alert>
</FieldSet> : null
}

View File

@@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import Alert from 'Components/Alert';
import FieldSet from 'Components/FieldSet';
import Form from 'Components/Form/Form';
import FormGroup from 'Components/Form/FormGroup';
@@ -7,7 +8,7 @@ import FormInputButton from 'Components/Form/FormInputButton';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes, sizes } from 'Helpers/Props';
import { inputTypes, kinds, sizes } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import NamingModal from './NamingModal';
import styles from './Naming.css';
@@ -110,9 +111,9 @@ class Naming extends Component {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadNamingSettings')}
</div>
</Alert>
}
{

View File

@@ -6,8 +6,9 @@ import FormGroup from 'Components/Form/FormGroup';
import FormInputGroup from 'Components/Form/FormInputGroup';
import FormLabel from 'Components/Form/FormLabel';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import { inputTypes } from 'Helpers/Props';
import { inputTypes, kinds } from 'Helpers/Props';
import translate from 'Utilities/String/translate';
import Alert from '../../../Components/Alert';
// Note: Do Not Translate Certification Countries
@@ -43,9 +44,9 @@ function MetadataOptions(props) {
{
!isFetching && error &&
<div>
<Alert kind={kinds.DANGER}>
{translate('UnableToLoadIndexerOptions')}
</div>
</Alert>
}
{

View File

@@ -141,7 +141,7 @@ class DelayProfile extends Component {
isOpen={this.state.isDeleteDelayProfileModalOpen}
kind={kinds.DANGER}
title={translate('DeleteDelayProfile')}
message={translate('AreYouSureYouWantToDeleteThisDelayProfile')}
message={translate('DeleteDelayProfileMessageText')}
confirmLabel={translate('Delete')}
onConfirm={this.onConfirmDeleteDelayProfile}
onCancel={this.onDeleteDelayProfileModalClose}

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