1
0
mirror of https://github.com/Radarr/Radarr.git synced 2026-04-18 21:35:51 -04:00

Compare commits

..

120 Commits

Author SHA1 Message Date
Bogdan 47360d4d38 Ensure movies without year are first in descending order 2023-07-29 18:06:07 +03:00
Bogdan 788782d009 Fixed: Ensure failing indexers are marked as failed when testing all
(cherry picked from commit b407eba61284d5fb855df6a2868805853aa6f448)
2023-07-29 09:34:12 +03:00
Bogdan 847d6244aa Convert formatCustomFormatScore to Typescript 2023-07-29 04:28:03 +03:00
Bogdan 8fd8128641 Add indexer default priority as constant 2023-07-29 04:23:26 +03:00
Bogdan 136075d233 Fixed: Check only enabled indexers in IndexerJackettAll health check 2023-07-29 04:22:01 +03:00
Servarr 02cec5312c Automated API Docs update 2023-07-28 13:01:41 +03:00
Weblate e5f728352c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ro/
Translation: Servarr/Radarr
2023-07-28 12:54:33 +03:00
Weblate 2cc1333e5c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: aguillement <adrien.guillement@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-07-27 12:42:33 +03:00
Bogdan a79980aae5 New: Add Monitored specification to Auto Tagging 2023-07-27 07:51:38 +03:00
Bogdan f2bbef75dd New: Add Year specification to Auto Tagging 2023-07-27 07:51:38 +03:00
Bogdan d5c1f58839 Fixed: Ensure validation for Auto Tagging specifications 2023-07-27 07:51:38 +03:00
Bogdan 430ea81937 Add translations to Auto Tagging 2023-07-27 07:51:38 +03:00
Mark McDowall 80099dcacb New: Auto tagging of movies
(cherry picked from commit 335fc05dd1595b6db912ebdde51ef4667963b37d)
2023-07-27 07:51:38 +03:00
Bogdan 938b69b240 Fixed: Add dedupe releases rule based on indexer priority 2023-07-26 11:36:59 +03:00
Bogdan 9839b482b2 New: Support for specific locale in Movie TitleFirstCharacter naming token
Fixes #8044
2023-07-26 03:28:55 +03:00
Servarr 4dbd962fca Automated API Docs update 2023-07-26 00:06:51 +03:00
Hayden 856c4fa4bb Fixed: Limit Discord embed title length to 256 characters
Co-authored-by: HeyBanditoz <7574664+HeyBanditoz@users.noreply.github.com>
(cherry picked from commit a6a61a016be777972f60f76a63d8e828f96a27cd)

Closes #8690
2023-07-25 23:55:18 +03:00
Mark McDowall 45f5ce5f29 Fixed: Prevent loss of restrictions when attempting to edit multiple restrictions at once
(cherry picked from commit b16094a9e3153f2ac39800475c1ddb1dafb6ab34)

Closes #8231
2023-07-25 23:31:46 +03:00
Mark McDowall 9d3e7f62ca Fixed: Overflowing release profile terms
(cherry picked from commit b90e25f652dcee3b9510a6f148a8d7a32a1ebe58)
2023-07-25 23:31:42 +03:00
Mark McDowall 594ed666e1 New: Ability to edit restriction terms
(cherry picked from commit dab6242ff28a603f2f15818c1c86567137ed0089)
2023-07-25 23:11:40 +03:00
jack-mil 36338310df New: Show Custom Format score in Manual Import
(cherry picked from commit 972e1408993fc4656196087c6646f23d222e41f5)

Closes #8839
2023-07-25 08:26:59 +03:00
Bogdan ffde07e4d6 Fix custom format translations 2023-07-25 07:59:41 +03:00
Weblate 90a1e1dbb3 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Fixer <ygj59783@zslsz.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: SHUAI.W <x@ousui.org>
Co-authored-by: Weblate <noreply@weblate.org>
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/zh_CN/
Translation: Servarr/Radarr
2023-07-25 07:35:00 +03:00
Qstick 8b5f305462 Remove old test 2023-07-24 23:09:58 -05:00
Qstick 2fe6847eb3 Fixed: False positives on selective Kodi library updates
Fixes #8879
2023-07-24 21:08:40 -05:00
Bogdan bf0f681d46 Fix children with the same key and make scrollTop optional 2023-07-24 11:40:50 +03:00
Bogdan f9cb4c1abd Fixed: More translations for columns 2023-07-24 11:40:50 +03:00
Bogdan 1190bf791c Fixed translations 2023-07-24 11:40:50 +03:00
Mark McDowall 53eb88d9a9 Fixed: Translations for columns
(cherry picked from commit 6d53d2a153a98070c42d0619c15902b6bd5dfab4)
2023-07-24 11:40:50 +03:00
Mark McDowall ed5c063127 Fixed: Improve translation loading
(cherry picked from commit 73c5ec1da4dd00301e1b0dddbcea37590a99b045)
2023-07-24 11:40:50 +03:00
Mark McDowall e691253419 UI loading improvements
Fixed: Caching for dynamically loaded JS files
Fixed: Incorrect caching of initialize.js
(cherry picked from commit f0cb5b81f140c67fa84162e094cc4e0f3476f5da)
2023-07-24 11:40:50 +03:00
Servarr 2959f72a10 Automated API Docs update 2023-07-24 04:51:11 +03:00
Mark McDowall 78ae059f3d Sort available filters options in custom filters
(cherry picked from commit 9e694c7b06c6d54fd652792fa1d81cc27ec1f311)
2023-07-24 04:43:42 +03:00
Qstick 7226cab3d8 Don't generate API docs for InitializeJson
Closes #8840

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2023-07-23 12:43:41 -05:00
Qstick 622162c5f6 Fixed: Default empty Tags for Collections
Fixes #8872
2023-07-23 12:33:04 -05:00
Bogdan e612d8c485 Update webpack, eslint and core-js 2023-07-23 11:45:14 +03:00
Bogdan b20e15855c Bump version to 4.7.3 2023-07-23 07:09:23 +03:00
Servarr 41e95ef98c Automated API Docs update 2023-07-23 04:35:23 +03:00
PearsonFlyer d8ba7f4d67 New: Ability to skip redownload when marking an item as failed from Activity Queue
(cherry picked from commit d7025a98deb321397db9a4933cf688b68eafeba9)

Closes #8861
2023-07-23 04:25:49 +03:00
Bogdan 97a28fee3b Add support for deprecated values in field select options
(cherry picked from commit d9786887f3fe30ef60ad9c50b3272bf60dfef309)
2023-07-23 04:02:14 +03:00
Bogdan e6b782aa20 New: Add hover background color to Series table
(cherry picked from commit 028152d732efb8d260dc2565df8b827a44523e37)
2023-07-23 04:01:32 +03:00
Bogdan 7aa72b30cb Cache busting for CSS files
(cherry picked from commit 38f263931ff8faba050762abe5fb692a5bc0d515)
2023-07-23 03:03:35 +03:00
bakerboy448 490a0cb2fb New: Log when testing for matching Remote Path Mapping
(cherry picked from commit 360d989cb047d0f752dd71b806aa0a746e3b5f3d)
2023-07-23 03:03:19 +03:00
Weblate fa50f60e6b 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-21 13:37:26 +03:00
Mark McDowall b5c9c996a5 Fix chunk IDs and source map file names
(cherry picked from commit bb8fed94eb2c44040031643e8c20ff72de759535)
2023-07-20 00:31:04 +03:00
Weblate 9b69d3b051 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-19 15:09:34 +03:00
Bogdan c8a1e49b7b Improve movie search results messaging 2023-07-19 06:25:01 +03:00
Weblate 0b300eee1c Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Qstick <qstick@gmail.com>
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/es/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-07-18 07:36:36 +03:00
Servarr ed107cadac Automated API Docs update 2023-07-18 07:36:02 +03:00
Bogdan a2216f23ec Add year to MovieTitleLink 2023-07-18 07:21:02 +03:00
Mark McDowall faaef80a80 New: Added UI for parsing release names
(cherry picked from commit 85e285598106346099ceae676599c5cb4b789c92)
2023-07-18 07:21:02 +03:00
Bogdan 5f70581a59 Use 2 spaces indentation for ts/tsx files
(cherry picked from commit bc374f07cebc8463c6416630d0fb06f011f21c31)
2023-07-18 06:50:11 +03:00
Bogdan 8369a77365 Fixed: Error when selecting different Quality Profile
(cherry picked from commit 5e19478266b33905e88b2e769269e44e5dd98e4b)
2023-07-18 06:49:47 +03:00
Weblate 00f4176dad Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Godwhitelight <godwhitelight1@gmail.com>
Co-authored-by: Guy Porat <guyporatmail@gmail.com>
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/he/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2023-07-17 20:21:18 -05:00
Weblate 056c224431 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Guy Porat <guyporatmail@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/he/
Translation: Servarr/Radarr
2023-07-17 06:36:50 +03:00
Anthony Ryan d84230d4cc Losslessly optimize images to save space 2023-07-16 21:46:19 -05:00
Weblate a6197ba70d Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: Anonymous <noreply@weblate.org>
Co-authored-by: BeardedWatermelon <periklis.karantonis@gmail.com>
Co-authored-by: Deamon1333 <deamon133@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Leliene <lhena.gardien@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 無情天 <kofzhanganguo@126.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/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/hr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/it/
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/th/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/uk/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2023-07-16 11:23:15 -05:00
Mark McDowall 31a16ab571 Fixed: Ensure translations are fetched before loading app
(cherry picked from commit ad2721dc55f3233e4c299babe5744418bc530418)
2023-07-16 08:27:04 +03:00
Bogdan 79c9225b00 Bump version to 4.7.2 2023-07-16 08:16:41 +03:00
Bogdan dd6be39063 Use named keys for apply tags help text 2023-07-16 05:21:18 +03:00
Weblate 668797b406 Multiple Translations updated by Weblate
ignore-downstream

Co-authored-by: BeardedWatermelon <periklis.karantonis@gmail.com>
Co-authored-by: Deamon1333 <deamon133@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Leliene <lhena.gardien@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: 無情天 <kofzhanganguo@126.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/el/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
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-16 05:10:50 +03:00
Bogdan 7bb9250877 Remove formatPreferredWordScore 2023-07-16 04:52:47 +03:00
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
426 changed files with 9806 additions and 2583 deletions
+1 -1
View File
@@ -270,7 +270,7 @@ dotnet_diagnostic.CA5397.severity = suggestion
dotnet_diagnostic.SYSLIB0006.severity = none dotnet_diagnostic.SYSLIB0006.severity = none
[*.{js,html,js,hbs,less,css}] [*.{js,html,hbs,less,css,ts,tsx}]
charset = utf-8 charset = utf-8
trim_trailing_whitespace = true trim_trailing_whitespace = true
insert_final_newline = true insert_final_newline = true
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 36 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 2.4 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 577 B

After

Width:  |  Height:  |  Size: 331 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 6.0 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 666 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 10 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

After

Width:  |  Height:  |  Size: 987 B

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 14 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 49 KiB

After

Width:  |  Height:  |  Size: 31 KiB

BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 21 KiB

+2 -2
View File
@@ -9,7 +9,7 @@ variables:
testsFolder: './_tests' testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '4.6.4' majorVersion: '4.7.3'
minorVersion: $[counter('minorVersion', 2000)] minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)' radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)' buildName: '$(Build.SourceBranchName).$(radarrVersion)'
@@ -363,7 +363,7 @@ stages:
- bash: | - bash: |
echo "Uploading source maps to sentry" echo "Uploading source maps to sentry"
curl -sL https://sentry.io/get-cli/ | bash 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 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 -p radarr-ui files "${RELEASENAME}" upload-sourcemaps _output/UI/ --rewrite
sentry-cli releases set-commits --auto "${RELEASENAME}" sentry-cli releases set-commits --auto "${RELEASENAME}"
+12 -9
View File
@@ -36,7 +36,7 @@ module.exports = (env) => {
}, },
entry: { entry: {
index: 'index.js' index: 'index.ts'
}, },
resolve: { resolve: {
@@ -66,23 +66,23 @@ module.exports = (env) => {
output: { output: {
path: distFolder, path: distFolder,
publicPath: '/', publicPath: '/',
filename: '[name].js', filename: '[name]-[contenthash].js',
sourceMapFilename: '[file].map' sourceMapFilename: '[file].map'
}, },
optimization: { optimization: {
moduleIds: 'deterministic', moduleIds: 'deterministic',
chunkIds: 'named', chunkIds: isProduction ? 'deterministic' : 'named'
splitChunks: {
chunks: 'initial',
name: 'vendors'
}
}, },
performance: { performance: {
hints: false hints: false
}, },
experiments: {
topLevelAwait: true
},
plugins: [ plugins: [
new webpack.DefinePlugin({ new webpack.DefinePlugin({
__DEV__: !isProduction, __DEV__: !isProduction,
@@ -90,13 +90,15 @@ module.exports = (env) => {
}), }),
new MiniCssExtractPlugin({ new MiniCssExtractPlugin({
filename: 'Content/styles.css' filename: 'Content/styles.css',
chunkFilename: 'Content/[id]-[chunkhash].css'
}), }),
new HtmlWebpackPlugin({ new HtmlWebpackPlugin({
template: 'frontend/src/index.ejs', template: 'frontend/src/index.ejs',
filename: 'index.html', filename: 'index.html',
publicPath: '/' publicPath: '/',
inject: false
}), }),
new FileManagerPlugin({ new FileManagerPlugin({
@@ -233,6 +235,7 @@ module.exports = (env) => {
{ {
loader: 'url-loader', loader: 'url-loader',
options: { options: {
limit: 10240,
mimetype: 'application/font-woff', mimetype: 'application/font-woff',
emitFile: false, emitFile: false,
name: 'Content/Fonts/[name].[ext]' name: 'Content/Fonts/[name].[ext]'
+14 -2
View File
@@ -4,7 +4,8 @@ import IconButton from 'Components/Link/IconButton';
import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector'; import RelativeDateCellConnector from 'Components/Table/Cells/RelativeDateCellConnector';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableRow from 'Components/Table/TableRow'; 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 MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage'; import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality'; import MovieQuality from 'Movie/MovieQuality';
@@ -176,7 +177,14 @@ class HistoryRow extends Component {
key={name} key={name}
className={styles.customFormatScore} className={styles.customFormatScore}
> >
{formatCustomFormatScore(customFormatScore)} <Tooltip
anchor={formatCustomFormatScore(
customFormatScore,
customFormats.length
)}
tooltip={<MovieFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell> </TableRowCell>
); );
} }
@@ -257,4 +265,8 @@ HistoryRow.propTypes = {
onMarkAsFailedPress: PropTypes.func.isRequired onMarkAsFailedPress: PropTypes.func.isRequired
}; };
HistoryRow.defaultProps = {
customFormats: []
};
export default HistoryRow; export default HistoryRow;
+6
View File
@@ -16,6 +16,12 @@
width: 150px; width: 150px;
} }
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;
}
.actions { .actions {
composes: cell from '~Components/Table/Cells/TableRowCell.css'; composes: cell from '~Components/Table/Cells/TableRowCell.css';
+1
View File
@@ -2,6 +2,7 @@
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
'actions': string; 'actions': string;
'customFormatScore': string;
'progress': string; 'progress': string;
'protocol': string; 'protocol': string;
'quality': string; 'quality': string;
+26 -3
View File
@@ -8,13 +8,15 @@ import ProgressBar from 'Components/ProgressBar';
import TableRowCell from 'Components/Table/Cells/TableRowCell'; import TableRowCell from 'Components/Table/Cells/TableRowCell';
import TableSelectCell from 'Components/Table/Cells/TableSelectCell'; import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
import TableRow from 'Components/Table/TableRow'; 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 InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
import MovieFormats from 'Movie/MovieFormats'; import MovieFormats from 'Movie/MovieFormats';
import MovieLanguage from 'Movie/MovieLanguage'; import MovieLanguage from 'Movie/MovieLanguage';
import MovieQuality from 'Movie/MovieQuality'; import MovieQuality from 'Movie/MovieQuality';
import MovieTitleLink from 'Movie/MovieTitleLink'; import MovieTitleLink from 'Movie/MovieTitleLink';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import QueueStatusCell from './QueueStatusCell'; import QueueStatusCell from './QueueStatusCell';
import RemoveQueueItemModal from './RemoveQueueItemModal'; import RemoveQueueItemModal from './RemoveQueueItemModal';
@@ -42,14 +44,14 @@ class QueueRow extends Component {
this.setState({ isRemoveQueueItemModalOpen: true }); this.setState({ isRemoveQueueItemModalOpen: true });
}; };
onRemoveQueueItemModalConfirmed = (blocklist) => { onRemoveQueueItemModalConfirmed = (blocklist, skipRedownload) => {
const { const {
onRemoveQueueItemPress, onRemoveQueueItemPress,
onQueueRowModalOpenOrClose onQueueRowModalOpenOrClose
} = this.props; } = this.props;
onQueueRowModalOpenOrClose(false); onQueueRowModalOpenOrClose(false);
onRemoveQueueItemPress(blocklist); onRemoveQueueItemPress(blocklist, skipRedownload);
this.setState({ isRemoveQueueItemModalOpen: false }); this.setState({ isRemoveQueueItemModalOpen: false });
}; };
@@ -88,6 +90,7 @@ class QueueRow extends Component {
movie, movie,
quality, quality,
customFormats, customFormats,
customFormatScore,
languages, languages,
protocol, protocol,
indexer, indexer,
@@ -201,6 +204,24 @@ class QueueRow extends Component {
); );
} }
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
<Tooltip
anchor={formatCustomFormatScore(
customFormatScore,
customFormats.length
)}
tooltip={<MovieFormats formats={customFormats} />}
position={tooltipPositions.BOTTOM}
/>
</TableRowCell>
);
}
if (name === 'protocol') { if (name === 'protocol') {
return ( return (
<TableRowCell key={name}> <TableRowCell key={name}>
@@ -365,6 +386,7 @@ QueueRow.propTypes = {
movie: PropTypes.object, movie: PropTypes.object,
quality: PropTypes.object.isRequired, quality: PropTypes.object.isRequired,
customFormats: PropTypes.arrayOf(PropTypes.object), customFormats: PropTypes.arrayOf(PropTypes.object),
customFormatScore: PropTypes.number.isRequired,
languages: PropTypes.arrayOf(PropTypes.object).isRequired, languages: PropTypes.arrayOf(PropTypes.object).isRequired,
protocol: PropTypes.string.isRequired, protocol: PropTypes.string.isRequired,
indexer: PropTypes.string, indexer: PropTypes.string,
@@ -390,6 +412,7 @@ QueueRow.propTypes = {
}; };
QueueRow.defaultProps = { QueueRow.defaultProps = {
customFormats: [],
isGrabbing: false, isGrabbing: false,
isRemoving: false isRemoving: false
}; };
@@ -22,7 +22,8 @@ class RemoveQueueItemModal extends Component {
this.state = { this.state = {
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}; };
} }
@@ -32,7 +33,8 @@ class RemoveQueueItemModal extends Component {
resetState = function() { resetState = function() {
this.setState({ this.setState({
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}); });
}; };
@@ -47,6 +49,10 @@ class RemoveQueueItemModal extends Component {
this.setState({ blocklist: value }); this.setState({ blocklist: value });
}; };
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => { onRemoveConfirmed = () => {
const state = this.state; const state = this.state;
@@ -70,7 +76,7 @@ class RemoveQueueItemModal extends Component {
isPending isPending
} = this.props; } = this.props;
const { remove, blocklist } = this.state; const { remove, blocklist, skipRedownload } = this.state;
return ( return (
<Modal <Modal
@@ -118,6 +124,20 @@ class RemoveQueueItemModal extends Component {
/> />
</FormGroup> </FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
@@ -23,7 +23,8 @@ class RemoveQueueItemsModal extends Component {
this.state = { this.state = {
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}; };
} }
@@ -33,7 +34,8 @@ class RemoveQueueItemsModal extends Component {
resetState = function() { resetState = function() {
this.setState({ this.setState({
remove: true, remove: true,
blocklist: false blocklist: false,
skipRedownload: false
}); });
}; };
@@ -48,6 +50,10 @@ class RemoveQueueItemsModal extends Component {
this.setState({ blocklist: value }); this.setState({ blocklist: value });
}; };
onSkipRedownloadChange = ({ value }) => {
this.setState({ skipRedownload: value });
};
onRemoveConfirmed = () => { onRemoveConfirmed = () => {
const state = this.state; const state = this.state;
@@ -71,7 +77,7 @@ class RemoveQueueItemsModal extends Component {
allPending allPending
} = this.props; } = this.props;
const { remove, blocklist } = this.state; const { remove, blocklist, skipRedownload } = this.state;
return ( return (
<Modal <Modal
@@ -122,6 +128,20 @@ class RemoveQueueItemsModal extends Component {
/> />
</FormGroup> </FormGroup>
{
blocklist ?
<FormGroup>
<FormLabel>{translate('SkipRedownload')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="skipRedownload"
value={skipRedownload}
helpText={translate('SkipRedownloadHelpText')}
onChange={this.onSkipRedownloadChange}
/>
</FormGroup> :
null
}
</ModalBody> </ModalBody>
<ModalFooter> <ModalFooter>
@@ -18,17 +18,23 @@ import styles from './ImportMovieSelectFolder.css';
const rootFolderColumns = [ const rootFolderColumns = [
{ {
name: 'path', name: 'path',
label: translate('Path'), get label() {
return translate('Path');
},
isVisible: true isVisible: true
}, },
{ {
name: 'freeSpace', name: 'freeSpace',
label: translate('FreeSpace'), get label() {
return translate('FreeSpace');
},
isVisible: true isVisible: true
}, },
{ {
name: 'unmappedFolders', name: 'unmappedFolders',
label: translate('UnmappedFolders'), get label() {
return translate('UnmappedFolders');
},
isVisible: true isVisible: true
}, },
{ {
+2 -2
View File
@@ -13,7 +13,7 @@ import Switch from 'Components/Router/Switch';
import DiscoverMovieConnector from 'DiscoverMovie/DiscoverMovieConnector'; import DiscoverMovieConnector from 'DiscoverMovie/DiscoverMovieConnector';
import MovieDetailsPageConnector from 'Movie/Details/MovieDetailsPageConnector'; import MovieDetailsPageConnector from 'Movie/Details/MovieDetailsPageConnector';
import MovieIndex from 'Movie/Index/MovieIndex'; import MovieIndex from 'Movie/Index/MovieIndex';
import CustomFormatSettingsConnector from 'Settings/CustomFormats/CustomFormatSettingsConnector'; import CustomFormatSettingsPage from 'Settings/CustomFormats/CustomFormatSettingsPage';
import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector'; import DownloadClientSettingsConnector from 'Settings/DownloadClients/DownloadClientSettingsConnector';
import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector'; import GeneralSettingsConnector from 'Settings/General/GeneralSettingsConnector';
import ImportListSettingsConnector from 'Settings/ImportLists/ImportListSettingsConnector'; import ImportListSettingsConnector from 'Settings/ImportLists/ImportListSettingsConnector';
@@ -148,7 +148,7 @@ function AppRoutes(props) {
<Route <Route
path="/settings/customformats" path="/settings/customformats"
component={CustomFormatSettingsConnector} component={CustomFormatSettingsPage}
/> />
<Route <Route
+2
View File
@@ -1,6 +1,7 @@
import InteractiveImportAppState from 'App/State/InteractiveImportAppState'; import InteractiveImportAppState from 'App/State/InteractiveImportAppState';
import MovieFilesAppState from './MovieFilesAppState'; import MovieFilesAppState from './MovieFilesAppState';
import MoviesAppState, { MovieIndexAppState } from './MoviesAppState'; import MoviesAppState, { MovieIndexAppState } from './MoviesAppState';
import ParseAppState from './ParseAppState';
import QueueAppState from './QueueAppState'; import QueueAppState from './QueueAppState';
import SettingsAppState from './SettingsAppState'; import SettingsAppState from './SettingsAppState';
import TagsAppState from './TagsAppState'; import TagsAppState from './TagsAppState';
@@ -41,6 +42,7 @@ interface AppState {
movieFiles: MovieFilesAppState; movieFiles: MovieFilesAppState;
interactiveImport: InteractiveImportAppState; interactiveImport: InteractiveImportAppState;
movieIndex: MovieIndexAppState; movieIndex: MovieIndexAppState;
parse: ParseAppState;
settings: SettingsAppState; settings: SettingsAppState;
movies: MoviesAppState; movies: MoviesAppState;
tags: TagsAppState; tags: TagsAppState;
+34
View File
@@ -0,0 +1,34 @@
import ModelBase from 'App/ModelBase';
import { AppSectionItemState } from 'App/State/AppSectionState';
import Language from 'Language/Language';
import Movie from 'Movie/Movie';
import { QualityModel } from 'Quality/Quality';
import CustomFormat from 'typings/CustomFormat';
export interface ParsedMovieInfo {
releaseTitle: string;
originalTitle: string;
movieTitle: string;
movieTitles: string[];
year: number;
quality: QualityModel;
languages: Language[];
releaseHash: string;
releaseGroup?: string;
edition?: string;
tmdbId?: number;
imdbId?: string;
}
export interface ParseModel extends ModelBase {
title: string;
parsedMovieInfo: ParsedMovieInfo;
movie?: Movie;
languages?: Language[];
customFormats?: CustomFormat[];
customFormatScore?: number;
}
type ParseAppState = AppSectionItemState<ParseModel>;
export default ParseAppState;
@@ -28,7 +28,7 @@ function createMapStateToProps() {
qualityProfileId: collection.qualityProfileId, qualityProfileId: collection.qualityProfileId,
minimumAvailability: collection.minimumAvailability, minimumAvailability: collection.minimumAvailability,
searchForMovie: collection.searchOnAdd, searchForMovie: collection.searchOnAdd,
tags: [] tags: collection.tags || []
}; };
const { const {
@@ -50,6 +50,7 @@ class EditCollectionModalContent extends Component {
minimumAvailability, minimumAvailability,
// Id, // Id,
rootFolderPath, rootFolderPath,
tags,
searchOnAdd searchOnAdd
} = item; } = item;
@@ -126,6 +127,17 @@ class EditCollectionModalContent extends Component {
/> />
</FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('Tags')}</FormLabel>
<FormInputGroup
type={inputTypes.TAG}
name="tags"
onChange={onInputChange}
{...tags}
/>
</FormGroup>
<FormGroup> <FormGroup>
<FormLabel>{translate('SearchOnAdd')}</FormLabel> <FormLabel>{translate('SearchOnAdd')}</FormLabel>
@@ -42,6 +42,7 @@ function createMapStateToProps() {
qualityProfileId: collection.qualityProfileId, qualityProfileId: collection.qualityProfileId,
minimumAvailability: collection.minimumAvailability, minimumAvailability: collection.minimumAvailability,
rootFolderPath: collection.rootFolderPath, rootFolderPath: collection.rootFolderPath,
tags: collection.tags,
searchOnAdd: collection.searchOnAdd searchOnAdd: collection.searchOnAdd
}; };
@@ -102,7 +102,7 @@ $hoverScale: 1.05;
position: relative; position: relative;
display: block; display: block;
background-color: var(--defaultColor); background-color: var(--black);
} }
.monitorToggleButton { .monitorToggleButton {
@@ -258,7 +258,7 @@ CollectionOverviews.propTypes = {
sortKey: PropTypes.string, sortKey: PropTypes.string,
overviewOptions: PropTypes.object.isRequired, overviewOptions: PropTypes.object.isRequired,
jumpToCharacter: PropTypes.string, jumpToCharacter: PropTypes.string,
scrollTop: PropTypes.number.isRequired, scrollTop: PropTypes.number,
scroller: PropTypes.instanceOf(Element).isRequired, scroller: PropTypes.instanceOf(Element).isRequired,
showRelativeDates: PropTypes.bool.isRequired, showRelativeDates: PropTypes.bool.isRequired,
shortDateFormat: PropTypes.string.isRequired, shortDateFormat: PropTypes.string.isRequired,
@@ -14,9 +14,24 @@ import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
const posterSizeOptions = [ const posterSizeOptions = [
{ key: 'small', value: translate('Small') }, {
{ key: 'medium', value: translate('Medium') }, key: 'small',
{ key: 'large', value: translate('Large') } get value() {
return translate('Small');
}
},
{
key: 'medium',
get value() {
return translate('Medium');
}
},
{
key: 'large',
get value() {
return translate('Large');
}
}
]; ];
class CollectionOverviewOptionsModalContent extends Component { class CollectionOverviewOptionsModalContent extends Component {
@@ -20,12 +20,16 @@ import styles from './FileBrowserModalContent.css';
const columns = [ const columns = [
{ {
name: 'type', name: 'type',
label: translate('Type'), get label() {
return translate('Type');
},
isVisible: true isVisible: true
}, },
{ {
name: 'name', name: 'name',
label: translate('Name'), get label() {
return translate('Name');
},
isVisible: true isVisible: true
} }
]; ];
@@ -10,12 +10,42 @@ import { NAME } from './FilterBuilderRowValue';
import styles from './DateFilterBuilderRowValue.css'; import styles from './DateFilterBuilderRowValue.css';
const timeOptions = [ const timeOptions = [
{ key: 'seconds', value: translate('Seconds') }, {
{ key: 'minutes', value: translate('Minutes') }, key: 'seconds',
{ key: 'hours', value: translate('Hours') }, get value() {
{ key: 'days', value: translate('Days') }, return translate('Seconds');
{ key: 'weeks', value: translate('Weeks') }, }
{ key: 'months', value: translate('Months') } },
{
key: 'minutes',
get value() {
return translate('Minutes');
}
},
{
key: 'hours',
get value() {
return translate('Hours');
}
},
{
key: 'days',
get value() {
return translate('Days');
}
},
{
key: 'weeks',
get value() {
return translate('Weeks');
}
},
{
key: 'months',
get value() {
return translate('Months');
}
}
]; ];
function isInFilter(filterType) { function isInFilter(filterType) {
@@ -210,11 +210,13 @@ class FilterBuilderRow extends Component {
const selectedFilterBuilderProp = this.selectedFilterBuilderProp; const selectedFilterBuilderProp = this.selectedFilterBuilderProp;
const keyOptions = filterBuilderProps.map((availablePropFilter) => { const keyOptions = filterBuilderProps.map((availablePropFilter) => {
const { name, label } = availablePropFilter;
return { return {
key: availablePropFilter.name, key: name,
value: availablePropFilter.label value: typeof label === 'function' ? label() : label
}; };
}); }).sort((a, b) => a.value.localeCompare(b.value));
const ValueComponent = getRowValueConnector(selectedFilterBuilderProp); const ValueComponent = getRowValueConnector(selectedFilterBuilderProp);
@@ -3,9 +3,24 @@ import translate from 'Utilities/String/translate';
import FilterBuilderRowValue from './FilterBuilderRowValue'; import FilterBuilderRowValue from './FilterBuilderRowValue';
const protocols = [ const protocols = [
{ id: 'announced', name: translate('Announced') }, {
{ id: 'inCinemas', name: translate('InCinemas') }, id: 'announced',
{ id: 'released', name: translate('Released') } get name() {
return translate('Announced');
}
},
{
id: 'inCinemas',
get name() {
return translate('InCinemas');
}
},
{
id: 'released',
get name() {
return translate('Released');
}
}
]; ];
function MinimumAvailabilityFilterBuilderRowValue(props) { function MinimumAvailabilityFilterBuilderRowValue(props) {
@@ -4,10 +4,30 @@ import FilterBuilderRowValue from './FilterBuilderRowValue';
const protocols = [ const protocols = [
{ id: 'tba', name: 'TBA' }, { id: 'tba', name: 'TBA' },
{ id: 'announced', name: translate('Announced') }, {
{ id: 'inCinemas', name: translate('InCinemas') }, id: 'announced',
{ id: 'released', name: translate('Released') }, get name() {
{ id: 'deleted', name: translate('Deleted') } return translate('Announced');
}
},
{
id: 'inCinemas',
get name() {
return translate('InCinemas');
}
},
{
id: 'released',
get name() {
return translate('Released');
}
},
{
id: 'deleted',
get name() {
return translate('Deleted');
}
}
]; ];
function ReleaseStatusFilterBuilderRowValue(props) { function ReleaseStatusFilterBuilderRowValue(props) {
@@ -4,9 +4,24 @@ import translate from 'Utilities/String/translate';
import EnhancedSelectInput from './EnhancedSelectInput'; import EnhancedSelectInput from './EnhancedSelectInput';
const availabilityOptions = [ const availabilityOptions = [
{ key: 'announced', value: translate('Announced') }, {
{ key: 'inCinemas', value: translate('InCinemas') }, key: 'announced',
{ key: 'released', value: translate('Released') } get value() {
return translate('Announced');
}
},
{
key: 'inCinemas',
get value() {
return translate('InCinemas');
}
},
{
key: 'released',
get value() {
return translate('Released');
}
}
]; ];
function AvailabilitySelectInput(props) { function AvailabilitySelectInput(props) {
@@ -20,7 +35,7 @@ function AvailabilitySelectInput(props) {
if (includeNoChange) { if (includeNoChange) {
values.unshift({ values.unshift({
key: 'noChange', key: 'noChange',
value: 'No Change', value: translate('NoChange'),
disabled: true disabled: true
}); });
} }
@@ -1,6 +1,7 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import monitorOptions from 'Utilities/Movie/monitorOptions'; import monitorOptions from 'Utilities/Movie/monitorOptions';
import translate from 'Utilities/String/translate';
import SelectInput from './SelectInput'; import SelectInput from './SelectInput';
function MovieMonitoredSelectInput(props) { function MovieMonitoredSelectInput(props) {
@@ -14,7 +15,7 @@ function MovieMonitoredSelectInput(props) {
if (includeNoChange) { if (includeNoChange) {
values.unshift({ values.unshift({
key: 'noChange', key: 'noChange',
value: 'No Change', value: translate('NoChange'),
disabled: true disabled: true
}); });
} }
@@ -35,6 +35,8 @@ function getType({ type, selectOptionsProviderAction }) {
return inputTypes.TEXT; return inputTypes.TEXT;
case 'oAuth': case 'oAuth':
return inputTypes.OAUTH; return inputTypes.OAUTH;
case 'rootFolder':
return inputTypes.ROOT_FOLDER_SELECT;
default: default:
return inputTypes.TEXT; return inputTypes.TEXT;
} }
@@ -5,6 +5,7 @@ import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector'; import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
import sortByName from 'Utilities/Array/sortByName'; import sortByName from 'Utilities/Array/sortByName';
import translate from 'Utilities/String/translate';
import EnhancedSelectInput from './EnhancedSelectInput'; import EnhancedSelectInput from './EnhancedSelectInput';
function createMapStateToProps() { function createMapStateToProps() {
@@ -24,7 +25,7 @@ function createMapStateToProps() {
if (includeNoChange) { if (includeNoChange) {
values.unshift({ values.unshift({
key: 'noChange', key: 'noChange',
value: 'No Change', value: translate('NoChange'),
disabled: includeNoChangeDisabled disabled: includeNoChangeDisabled
}); });
} }
@@ -69,7 +70,7 @@ class QualityProfileSelectInputConnector extends Component {
// Listeners // Listeners
onChange = ({ name, value }) => { onChange = ({ name, value }) => {
this.props.onChange({ name, value: parseInt(value) }); this.props.onChange({ name, value: value === 'noChange' ? value : parseInt(value) });
}; };
// //
@@ -3,6 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { addRootFolder } from 'Store/Actions/rootFolderActions'; import { addRootFolder } from 'Store/Actions/rootFolderActions';
import translate from 'Utilities/String/translate';
import RootFolderSelectInput from './RootFolderSelectInput'; import RootFolderSelectInput from './RootFolderSelectInput';
const ADD_NEW_KEY = 'addNew'; const ADD_NEW_KEY = 'addNew';
@@ -27,7 +28,7 @@ function createMapStateToProps() {
if (includeNoChange) { if (includeNoChange) {
values.unshift({ values.unshift({
key: 'noChange', key: 'noChange',
value: 'No Change', value: translate('NoChange'),
isDisabled: includeNoChangeDisabled, isDisabled: includeNoChangeDisabled,
isMissing: false isMissing: false
}); });
+2 -2
View File
@@ -61,7 +61,7 @@ class SelectInput extends Component {
value={key} value={key}
{...otherOptionProps} {...otherOptionProps}
> >
{optionValue} {typeof optionValue === 'function' ? optionValue() : optionValue}
</option> </option>
); );
}) })
@@ -75,7 +75,7 @@ SelectInput.propTypes = {
className: PropTypes.string, className: PropTypes.string,
disabledClassName: PropTypes.string, disabledClassName: PropTypes.string,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, value: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.func]).isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired, values: PropTypes.arrayOf(PropTypes.object).isRequired,
isDisabled: PropTypes.bool, isDisabled: PropTypes.bool,
hasError: PropTypes.bool, hasError: PropTypes.bool,
+20 -2
View File
@@ -75,6 +75,18 @@ class TagInput extends Component {
// //
// Listeners // Listeners
onTagEdit = ({ value, ...otherProps }) => {
const currentValue = this.state.value;
if (currentValue && this.props.onTagReplace) {
this.props.onTagReplace(otherProps, { name: currentValue });
} else {
this.props.onTagDelete(otherProps);
}
this.setState({ value });
};
onInputContainerPress = () => { onInputContainerPress = () => {
this._autosuggestRef.input.focus(); this._autosuggestRef.input.focus();
}; };
@@ -188,6 +200,7 @@ class TagInput extends Component {
const { const {
tags, tags,
kind, kind,
canEdit,
tagComponent, tagComponent,
onTagDelete onTagDelete
} = this.props; } = this.props;
@@ -199,8 +212,10 @@ class TagInput extends Component {
kind={kind} kind={kind}
inputProps={inputProps} inputProps={inputProps}
isFocused={this.state.isFocused} isFocused={this.state.isFocused}
canEdit={canEdit}
tagComponent={tagComponent} tagComponent={tagComponent}
onTagDelete={onTagDelete} onTagDelete={onTagDelete}
onTagEdit={this.onTagEdit}
onInputContainerPress={this.onInputContainerPress} onInputContainerPress={this.onInputContainerPress}
/> />
); );
@@ -223,7 +238,7 @@ class TagInput extends Component {
<AutoSuggestInput <AutoSuggestInput
{...otherProps} {...otherProps}
forwardedRef={this._setAutosuggestRef} forwardedRef={this._setAutosuggestRef}
className={styles.internalInput} className={className}
inputContainerClassName={classNames( inputContainerClassName={classNames(
inputContainerClassName, inputContainerClassName,
isFocused && styles.isFocused isFocused && styles.isFocused
@@ -258,11 +273,13 @@ TagInput.propTypes = {
placeholder: PropTypes.string.isRequired, placeholder: PropTypes.string.isRequired,
delimiters: PropTypes.arrayOf(PropTypes.string).isRequired, delimiters: PropTypes.arrayOf(PropTypes.string).isRequired,
minQueryLength: PropTypes.number.isRequired, minQueryLength: PropTypes.number.isRequired,
canEdit: PropTypes.bool,
hasError: PropTypes.bool, hasError: PropTypes.bool,
hasWarning: PropTypes.bool, hasWarning: PropTypes.bool,
tagComponent: PropTypes.elementType.isRequired, tagComponent: PropTypes.elementType.isRequired,
onTagAdd: PropTypes.func.isRequired, onTagAdd: PropTypes.func.isRequired,
onTagDelete: PropTypes.func.isRequired onTagDelete: PropTypes.func.isRequired,
onTagReplace: PropTypes.func
}; };
TagInput.defaultProps = { TagInput.defaultProps = {
@@ -273,6 +290,7 @@ TagInput.defaultProps = {
placeholder: '', placeholder: '',
delimiters: ['Tab', 'Enter', ' ', ','], delimiters: ['Tab', 'Enter', ' ', ','],
minQueryLength: 1, minQueryLength: 1,
canEdit: false,
tagComponent: TagInputTag tagComponent: TagInputTag
}; };
@@ -138,6 +138,7 @@ class TagInputConnector extends Component {
<TagInput <TagInput
onTagAdd={this.onTagAdd} onTagAdd={this.onTagAdd}
onTagDelete={this.onTagDelete} onTagDelete={this.onTagDelete}
onTagReplace={this.onTagReplace}
{...this.props} {...this.props}
/> />
); );
@@ -28,8 +28,10 @@ class TagInputInput extends Component {
tags, tags,
inputProps, inputProps,
kind, kind,
canEdit,
tagComponent: TagComponent, tagComponent: TagComponent,
onTagDelete onTagDelete,
onTagEdit
} = this.props; } = this.props;
return ( return (
@@ -46,8 +48,10 @@ class TagInputInput extends Component {
index={index} index={index}
tag={tag} tag={tag}
kind={kind} kind={kind}
canEdit={canEdit}
isLastTag={index === tags.length - 1} isLastTag={index === tags.length - 1}
onDelete={onTagDelete} onDelete={onTagDelete}
onEdit={onTagEdit}
/> />
); );
}) })
@@ -66,8 +70,10 @@ TagInputInput.propTypes = {
inputProps: PropTypes.object.isRequired, inputProps: PropTypes.object.isRequired,
kind: PropTypes.oneOf(kinds.all).isRequired, kind: PropTypes.oneOf(kinds.all).isRequired,
isFocused: PropTypes.bool.isRequired, isFocused: PropTypes.bool.isRequired,
canEdit: PropTypes.bool.isRequired,
tagComponent: PropTypes.elementType.isRequired, tagComponent: PropTypes.elementType.isRequired,
onTagDelete: PropTypes.func.isRequired, onTagDelete: PropTypes.func.isRequired,
onTagEdit: PropTypes.func.isRequired,
onInputContainerPress: PropTypes.func.isRequired onInputContainerPress: PropTypes.func.isRequired
}; };
+37 -2
View File
@@ -1,5 +1,40 @@
.tag { .tag {
composes: link from '~Components/Link/Link.css'; display: flex;
justify-content: center;
flex-direction: column;
max-width: 100%;
height: 31px; height: 31px;
} }
.link {
composes: link from '~Components/Link/Link.css';
max-width: 100%;
line-height: 1px;
}
.linkWithEdit {
composes: link from '~Components/Link/Link.css';
max-width: calc(100% - 9px - 4px - 2px);
line-height: 1px;
}
.editContainer {
display: inline-block;
margin-left: 4px;
padding-left: 2px;
border-left: 1px solid #eee;
}
.editButton {
composes: button from '~Components/Link/IconButton.css';
width: 9px;
}
.label {
composes: label from '~Components/Label.css';
max-width: 100%;
}
+5
View File
@@ -1,6 +1,11 @@
// This file is automatically generated. // This file is automatically generated.
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
'editButton': string;
'editContainer': string;
'label': string;
'link': string;
'linkWithEdit': string;
'tag': string; 'tag': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;
+48 -8
View File
@@ -1,8 +1,9 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import Label from 'Components/Label'; import Label from 'Components/Label';
import IconButton from 'Components/Link/IconButton';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import { kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
import tagShape from 'Helpers/Props/Shapes/tagShape'; import tagShape from 'Helpers/Props/Shapes/tagShape';
import styles from './TagInputTag.css'; import styles from './TagInputTag.css';
@@ -24,24 +25,61 @@ class TagInputTag extends Component {
}); });
}; };
onEdit = () => {
const {
index,
tag,
onEdit
} = this.props;
onEdit({
index,
id: tag.id,
value: tag.name
});
};
// //
// Render // Render
render() { render() {
const { const {
tag, tag,
kind kind,
canEdit
} = this.props; } = this.props;
return ( return (
<Link <div
className={styles.tag} className={styles.tag}
tabIndex={-1} tabIndex={-1}
onPress={this.onDelete}
> >
<Label kind={kind}> <Label
{tag.name} className={styles.label}
kind={kind}
>
<Link
className={canEdit ? styles.linkWithEdit : styles.link}
tabIndex={-1}
onPress={this.onDelete}
>
{tag.name}
</Link>
{
canEdit ?
<div className={styles.editContainer}>
<IconButton
className={styles.editButton}
name={icons.EDIT}
size={9}
onPress={this.onEdit}
/>
</div> :
null
}
</Label> </Label>
</Link> </div>
); );
} }
} }
@@ -50,7 +88,9 @@ TagInputTag.propTypes = {
index: PropTypes.number.isRequired, index: PropTypes.number.isRequired,
tag: PropTypes.shape(tagShape), tag: PropTypes.shape(tagShape),
kind: PropTypes.oneOf(kinds.all).isRequired, kind: PropTypes.oneOf(kinds.all).isRequired,
onDelete: PropTypes.func.isRequired canEdit: PropTypes.bool.isRequired,
onDelete: PropTypes.func.isRequired,
onEdit: PropTypes.func.isRequired
}; };
export default TagInputTag; export default TagInputTag;
@@ -71,6 +71,20 @@ class TextTagInputConnector extends Component {
}); });
}; };
onTagReplace = (tagToReplace, newTag) => {
const {
name,
valueArray,
onChange
} = this.props;
const newValue = [...valueArray];
newValue.splice(tagToReplace.index, 1);
newValue.push(newTag.name.trim());
onChange({ name, value: newValue });
};
// //
// Render // Render
@@ -80,6 +94,7 @@ class TextTagInputConnector extends Component {
tagList={[]} tagList={[]}
onTagAdd={this.onTagAdd} onTagAdd={this.onTagAdd}
onTagDelete={this.onTagDelete} onTagDelete={this.onTagDelete}
onTagReplace={this.onTagReplace}
{...this.props} {...this.props}
/> />
); );
+2 -2
View File
@@ -41,7 +41,7 @@ class Icon extends PureComponent {
return ( return (
<span <span
className={containerClassName} className={containerClassName}
title={title} title={typeof title === 'function' ? title() : title}
> >
{icon} {icon}
</span> </span>
@@ -58,7 +58,7 @@ Icon.propTypes = {
name: PropTypes.object.isRequired, name: PropTypes.object.isRequired,
kind: PropTypes.string.isRequired, kind: PropTypes.string.isRequired,
size: PropTypes.number.isRequired, size: PropTypes.number.isRequired,
title: PropTypes.string, title: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
isSpinning: PropTypes.bool.isRequired, isSpinning: PropTypes.bool.isRequired,
fixedWidth: PropTypes.bool.isRequired fixedWidth: PropTypes.bool.isRequired
}; };
@@ -33,7 +33,7 @@ class FilterMenuContent extends Component {
selectedFilterKey={selectedFilterKey} selectedFilterKey={selectedFilterKey}
onPress={onFilterSelect} onPress={onFilterSelect}
> >
{filter.label} {typeof filter.label === 'function' ? filter.label() : filter.label}
</FilterMenuItem> </FilterMenuItem>
); );
}) })
@@ -7,6 +7,7 @@ function ErrorPage(props) {
const { const {
version, version,
isLocalStorageSupported, isLocalStorageSupported,
translationsError,
moviesError, moviesError,
customFiltersError, customFiltersError,
tagsError, tagsError,
@@ -20,6 +21,8 @@ function ErrorPage(props) {
if (!isLocalStorageSupported) { if (!isLocalStorageSupported) {
errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.'; errorMessage = 'Local Storage is not supported or disabled. A plugin or private browsing may have disabled it.';
} else if (translationsError) {
errorMessage = getErrorMessage(translationsError, 'Failed to load translations from API');
} else if (moviesError) { } else if (moviesError) {
errorMessage = getErrorMessage(moviesError, 'Failed to load movie from API'); errorMessage = getErrorMessage(moviesError, 'Failed to load movie from API');
} else if (customFiltersError) { } else if (customFiltersError) {
@@ -52,6 +55,7 @@ function ErrorPage(props) {
ErrorPage.propTypes = { ErrorPage.propTypes = {
version: PropTypes.string.isRequired, version: PropTypes.string.isRequired,
isLocalStorageSupported: PropTypes.bool.isRequired, isLocalStorageSupported: PropTypes.bool.isRequired,
translationsError: PropTypes.object,
moviesError: PropTypes.object, moviesError: PropTypes.object,
customFiltersError: PropTypes.object, customFiltersError: PropTypes.object,
tagsError: PropTypes.object, tagsError: PropTypes.object,
+19 -6
View File
@@ -3,7 +3,7 @@ import React, { Component } from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom'; import { withRouter } from 'react-router-dom';
import { createSelector } from 'reselect'; import { createSelector } from 'reselect';
import { saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions'; import { fetchTranslations, saveDimensions, setIsSidebarVisible } from 'Store/Actions/appActions';
import { fetchCustomFilters } from 'Store/Actions/customFilterActions'; import { fetchCustomFilters } from 'Store/Actions/customFilterActions';
import { fetchMovies } from 'Store/Actions/movieActions'; import { fetchMovies } from 'Store/Actions/movieActions';
import { fetchMovieCollections } from 'Store/Actions/movieCollectionActions'; import { fetchMovieCollections } from 'Store/Actions/movieCollectionActions';
@@ -53,6 +53,7 @@ const selectIsPopulated = createSelector(
(state) => state.settings.importLists.isPopulated, (state) => state.settings.importLists.isPopulated,
(state) => state.system.status.isPopulated, (state) => state.system.status.isPopulated,
(state) => state.movieCollections.isPopulated, (state) => state.movieCollections.isPopulated,
(state) => state.app.translations.isPopulated,
( (
customFiltersIsPopulated, customFiltersIsPopulated,
tagsIsPopulated, tagsIsPopulated,
@@ -62,7 +63,8 @@ const selectIsPopulated = createSelector(
indexerFlagsIsPopulated, indexerFlagsIsPopulated,
importListsIsPopulated, importListsIsPopulated,
systemStatusIsPopulated, systemStatusIsPopulated,
movieCollectionsIsPopulated movieCollectionsIsPopulated,
translationsIsPopulated
) => { ) => {
return ( return (
customFiltersIsPopulated && customFiltersIsPopulated &&
@@ -73,7 +75,8 @@ const selectIsPopulated = createSelector(
indexerFlagsIsPopulated && indexerFlagsIsPopulated &&
importListsIsPopulated && importListsIsPopulated &&
systemStatusIsPopulated && systemStatusIsPopulated &&
movieCollectionsIsPopulated movieCollectionsIsPopulated &&
translationsIsPopulated
); );
} }
); );
@@ -88,6 +91,7 @@ const selectErrors = createSelector(
(state) => state.settings.importLists.error, (state) => state.settings.importLists.error,
(state) => state.system.status.error, (state) => state.system.status.error,
(state) => state.movieCollections.error, (state) => state.movieCollections.error,
(state) => state.app.translations.error,
( (
customFiltersError, customFiltersError,
tagsError, tagsError,
@@ -97,7 +101,8 @@ const selectErrors = createSelector(
indexerFlagsError, indexerFlagsError,
importListsError, importListsError,
systemStatusError, systemStatusError,
movieCollectionsError movieCollectionsError,
translationsError
) => { ) => {
const hasError = !!( const hasError = !!(
customFiltersError || customFiltersError ||
@@ -108,7 +113,8 @@ const selectErrors = createSelector(
indexerFlagsError || indexerFlagsError ||
importListsError || importListsError ||
systemStatusError || systemStatusError ||
movieCollectionsError movieCollectionsError ||
translationsError
); );
return { return {
@@ -121,7 +127,8 @@ const selectErrors = createSelector(
indexerFlagsError, indexerFlagsError,
importListsError, importListsError,
systemStatusError, systemStatusError,
movieCollectionsError movieCollectionsError,
translationsError
}; };
} }
); );
@@ -183,6 +190,9 @@ function createMapDispatchToProps(dispatch, props) {
dispatchFetchStatus() { dispatchFetchStatus() {
dispatch(fetchStatus()); dispatch(fetchStatus());
}, },
dispatchFetchTranslations() {
dispatch(fetchTranslations());
},
onResize(dimensions) { onResize(dimensions) {
dispatch(saveDimensions(dimensions)); dispatch(saveDimensions(dimensions));
}, },
@@ -217,6 +227,7 @@ class PageConnector extends Component {
this.props.dispatchFetchImportLists(); this.props.dispatchFetchImportLists();
this.props.dispatchFetchUISettings(); this.props.dispatchFetchUISettings();
this.props.dispatchFetchStatus(); this.props.dispatchFetchStatus();
this.props.dispatchFetchTranslations();
} }
} }
@@ -243,6 +254,7 @@ class PageConnector extends Component {
dispatchFetchImportLists, dispatchFetchImportLists,
dispatchFetchUISettings, dispatchFetchUISettings,
dispatchFetchStatus, dispatchFetchStatus,
dispatchFetchTranslations,
...otherProps ...otherProps
} = this.props; } = this.props;
@@ -284,6 +296,7 @@ PageConnector.propTypes = {
dispatchFetchImportLists: PropTypes.func.isRequired, dispatchFetchImportLists: PropTypes.func.isRequired,
dispatchFetchUISettings: PropTypes.func.isRequired, dispatchFetchUISettings: PropTypes.func.isRequired,
dispatchFetchStatus: PropTypes.func.isRequired, dispatchFetchStatus: PropTypes.func.isRequired,
dispatchFetchTranslations: PropTypes.func.isRequired,
onSidebarVisibleChange: PropTypes.func.isRequired onSidebarVisibleChange: PropTypes.func.isRequired
}; };
@@ -5,8 +5,8 @@ import { isLocked } from 'Utilities/scrollLock';
import styles from './PageContentBody.css'; import styles from './PageContentBody.css';
interface PageContentBodyProps { interface PageContentBodyProps {
className: string; className?: string;
innerClassName: string; innerClassName?: string;
children: ReactNode; children: ReactNode;
initialScrollTop?: number; initialScrollTop?: number;
onScroll?: (payload: OnScroll) => void; onScroll?: (payload: OnScroll) => void;
@@ -21,24 +21,34 @@ const SIDEBAR_WIDTH = parseInt(dimensions.sidebarWidth);
const links = [ const links = [
{ {
iconName: icons.MOVIE_CONTINUING, iconName: icons.MOVIE_CONTINUING,
title: translate('Movies'), get title() {
return translate('Movies');
},
to: '/', to: '/',
alias: '/movies', alias: '/movies',
children: [ children: [
{ {
title: translate('AddNew'), get title() {
return translate('AddNew');
},
to: '/add/new' to: '/add/new'
}, },
{ {
title: translate('ImportLibrary'), get title() {
return translate('ImportLibrary');
},
to: '/add/import' to: '/add/import'
}, },
{ {
title: translate('Collections'), get title() {
return translate('Collections');
},
to: '/collections' to: '/collections'
}, },
{ {
title: translate('Discover'), get title() {
return translate('Discover');
},
to: '/add/discover' to: '/add/discover'
} }
] ]
@@ -46,26 +56,36 @@ const links = [
{ {
iconName: icons.CALENDAR, iconName: icons.CALENDAR,
title: translate('Calendar'), get title() {
return translate('Calendar');
},
to: '/calendar' to: '/calendar'
}, },
{ {
iconName: icons.ACTIVITY, iconName: icons.ACTIVITY,
title: translate('Activity'), get title() {
return translate('Activity');
},
to: '/activity/queue', to: '/activity/queue',
children: [ children: [
{ {
title: translate('Queue'), get title() {
return translate('Queue');
},
to: '/activity/queue', to: '/activity/queue',
statusComponent: QueueStatusConnector statusComponent: QueueStatusConnector
}, },
{ {
title: translate('History'), get title() {
return translate('History');
},
to: '/activity/history' to: '/activity/history'
}, },
{ {
title: translate('Blocklist'), get title() {
return translate('Blocklist');
},
to: '/activity/blocklist' to: '/activity/blocklist'
} }
] ]
@@ -73,55 +93,81 @@ const links = [
{ {
iconName: icons.SETTINGS, iconName: icons.SETTINGS,
title: translate('Settings'), get title() {
return translate('Settings');
},
to: '/settings', to: '/settings',
children: [ children: [
{ {
title: translate('MediaManagement'), get title() {
return translate('MediaManagement');
},
to: '/settings/mediamanagement' to: '/settings/mediamanagement'
}, },
{ {
title: translate('Profiles'), get title() {
return translate('Profiles');
},
to: '/settings/profiles' to: '/settings/profiles'
}, },
{ {
title: translate('Quality'), get title() {
return translate('Quality');
},
to: '/settings/quality' to: '/settings/quality'
}, },
{ {
title: translate('CustomFormats'), get title() {
return translate('CustomFormats');
},
to: '/settings/customformats' to: '/settings/customformats'
}, },
{ {
title: translate('Indexers'), get title() {
return translate('Indexers');
},
to: '/settings/indexers' to: '/settings/indexers'
}, },
{ {
title: translate('DownloadClients'), get title() {
return translate('DownloadClients');
},
to: '/settings/downloadclients' to: '/settings/downloadclients'
}, },
{ {
title: translate('Lists'), get title() {
return translate('Lists');
},
to: '/settings/importlists' to: '/settings/importlists'
}, },
{ {
title: translate('Connect'), get title() {
return translate('Connect');
},
to: '/settings/connect' to: '/settings/connect'
}, },
{ {
title: translate('Metadata'), get title() {
return translate('Metadata');
},
to: '/settings/metadata' to: '/settings/metadata'
}, },
{ {
title: translate('Tags'), get title() {
return translate('Tags');
},
to: '/settings/tags' to: '/settings/tags'
}, },
{ {
title: translate('General'), get title() {
return translate('General');
},
to: '/settings/general' to: '/settings/general'
}, },
{ {
title: translate('UI'), get title() {
return translate('UI');
},
to: '/settings/ui' to: '/settings/ui'
} }
] ]
@@ -129,32 +175,46 @@ const links = [
{ {
iconName: icons.SYSTEM, iconName: icons.SYSTEM,
title: translate('System'), get title() {
return translate('System');
},
to: '/system/status', to: '/system/status',
children: [ children: [
{ {
title: translate('Status'), get title() {
return translate('Status');
},
to: '/system/status', to: '/system/status',
statusComponent: HealthStatusConnector statusComponent: HealthStatusConnector
}, },
{ {
title: translate('Tasks'), get title() {
return translate('Tasks');
},
to: '/system/tasks' to: '/system/tasks'
}, },
{ {
title: translate('Backup'), get title() {
return translate('Backup');
},
to: '/system/backup' to: '/system/backup'
}, },
{ {
title: translate('Updates'), get title() {
return translate('Updates');
},
to: '/system/updates' to: '/system/updates'
}, },
{ {
title: translate('Events'), get title() {
return translate('Events');
},
to: '/system/events' to: '/system/events'
}, },
{ {
title: translate('LogFiles'), get title() {
return translate('LogFiles');
},
to: '/system/logs/files' to: '/system/logs/files'
} }
] ]
+3 -1
View File
@@ -1,8 +1,10 @@
import React from 'react'; import React from 'react';
type PropertyFunction<T> = () => T;
interface Column { interface Column {
name: string; name: string;
label: string | React.ReactNode; label: string | PropertyFunction<string> | React.ReactNode;
columnLabel?: string; columnLabel?: string;
isSortable?: boolean; isSortable?: boolean;
isVisible: boolean; isVisible: boolean;
+1 -1
View File
@@ -107,7 +107,7 @@ function Table(props) {
{...getTableHeaderCellProps(otherProps)} {...getTableHeaderCellProps(otherProps)}
{...column} {...column}
> >
{column.label} {typeof column.label === 'function' ? column.label() : column.label}
</TableHeaderCell> </TableHeaderCell>
); );
}) })
@@ -30,6 +30,7 @@ class TableHeaderCell extends Component {
const { const {
className, className,
name, name,
label,
columnLabel, columnLabel,
isSortable, isSortable,
isVisible, isVisible,
@@ -53,7 +54,8 @@ class TableHeaderCell extends Component {
{...otherProps} {...otherProps}
component="th" component="th"
className={className} className={className}
title={columnLabel} label={typeof label === 'function' ? label() : label}
title={typeof columnLabel === 'function' ? columnLabel() : columnLabel}
onPress={this.onPress} onPress={this.onPress}
> >
{children} {children}
@@ -77,7 +79,8 @@ class TableHeaderCell extends Component {
TableHeaderCell.propTypes = { TableHeaderCell.propTypes = {
className: PropTypes.string, className: PropTypes.string,
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
columnLabel: PropTypes.string, label: PropTypes.oneOfType([PropTypes.string, PropTypes.func, PropTypes.node]),
columnLabel: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
isSortable: PropTypes.bool, isSortable: PropTypes.bool,
isVisible: PropTypes.bool, isVisible: PropTypes.bool,
isModifiable: PropTypes.bool, isModifiable: PropTypes.bool,
@@ -35,7 +35,7 @@ function TableOptionsColumn(props) {
isDisabled={isModifiable === false} isDisabled={isModifiable === false}
onChange={onVisibleChange} onChange={onVisibleChange}
/> />
{label} {typeof label === 'function' ? label() : label}
</label> </label>
{ {
@@ -56,7 +56,7 @@ function TableOptionsColumn(props) {
TableOptionsColumn.propTypes = { TableOptionsColumn.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
isVisible: PropTypes.bool.isRequired, isVisible: PropTypes.bool.isRequired,
isModifiable: PropTypes.bool.isRequired, isModifiable: PropTypes.bool.isRequired,
index: PropTypes.number.isRequired, index: PropTypes.number.isRequired,
@@ -112,7 +112,7 @@ class TableOptionsColumnDragSource extends Component {
<TableOptionsColumn <TableOptionsColumn
name={name} name={name}
label={label} label={typeof label === 'function' ? label() : label}
isVisible={isVisible} isVisible={isVisible}
isModifiable={isModifiable} isModifiable={isModifiable}
index={index} index={index}
@@ -138,7 +138,7 @@ class TableOptionsColumnDragSource extends Component {
TableOptionsColumnDragSource.propTypes = { TableOptionsColumnDragSource.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
label: PropTypes.string.isRequired, label: PropTypes.oneOfType([PropTypes.string, PropTypes.func]).isRequired,
isVisible: PropTypes.bool.isRequired, isVisible: PropTypes.bool.isRequired,
isModifiable: PropTypes.bool.isRequired, isModifiable: PropTypes.bool.isRequired,
index: PropTypes.number.isRequired, index: PropTypes.number.isRequired,
+27 -9
View File
@@ -6,47 +6,65 @@ import translate from 'Utilities/String/translate';
export const shortcuts = { export const shortcuts = {
OPEN_KEYBOARD_SHORTCUTS_MODAL: { OPEN_KEYBOARD_SHORTCUTS_MODAL: {
key: '?', key: '?',
name: translate('OpenThisModal') get name() {
return translate('OpenThisModal');
}
}, },
CLOSE_MODAL: { CLOSE_MODAL: {
key: 'Esc', key: 'Esc',
name: translate('CloseCurrentModal') get name() {
return translate('CloseCurrentModal');
}
}, },
ACCEPT_CONFIRM_MODAL: { ACCEPT_CONFIRM_MODAL: {
key: 'Enter', key: 'Enter',
name: translate('AcceptConfirmationModal') get name() {
return translate('AcceptConfirmationModal');
}
}, },
MOVIE_SEARCH_INPUT: { MOVIE_SEARCH_INPUT: {
key: 's', key: 's',
name: translate('FocusSearchBox') get name() {
return translate('FocusSearchBox');
}
}, },
SAVE_SETTINGS: { SAVE_SETTINGS: {
key: 'mod+s', key: 'mod+s',
name: translate('SaveSettings') get name() {
return translate('SaveSettings');
}
}, },
SCROLL_TOP: { SCROLL_TOP: {
key: 'mod+home', key: 'mod+home',
name: translate('MovieIndexScrollTop') get name() {
return translate('MovieIndexScrollTop');
}
}, },
SCROLL_BOTTOM: { SCROLL_BOTTOM: {
key: 'mod+end', key: 'mod+end',
name: translate('MovieIndexScrollBottom') get name() {
return translate('MovieIndexScrollBottom');
}
}, },
DETAILS_NEXT: { DETAILS_NEXT: {
key: '→', key: '→',
name: translate('MovieDetailsNextMovie') get name() {
return translate('MovieDetailsNextMovie');
}
}, },
DETAILS_PREVIOUS: { DETAILS_PREVIOUS: {
key: '←', key: '←',
name: translate('MovieDetailsPreviousMovie') get name() {
return translate('MovieDetailsPreviousMovie');
}
} }
}; };
Binary file not shown.

Before

Width:  |  Height:  |  Size: 101 KiB

After

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.7 KiB

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 28 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.3 KiB

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 611 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 549 B

After

Width:  |  Height:  |  Size: 337 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 623 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.5 KiB

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 115 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 953 B

After

Width:  |  Height:  |  Size: 592 B

@@ -14,9 +14,24 @@ import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
const posterSizeOptions = [ const posterSizeOptions = [
{ key: 'small', value: translate('Small') }, {
{ key: 'medium', value: translate('Medium') }, key: 'small',
{ key: 'large', value: translate('Large') } get value() {
return translate('Small');
}
},
{
key: 'medium',
get value() {
return translate('Medium');
}
},
{
key: 'large',
get value() {
return translate('Large');
}
}
]; ];
class DiscoverMovieOverviewOptionsModalContent extends Component { class DiscoverMovieOverviewOptionsModalContent extends Component {
@@ -14,9 +14,24 @@ import { inputTypes } from 'Helpers/Props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
const posterSizeOptions = [ const posterSizeOptions = [
{ key: 'small', value: translate('Small') }, {
{ key: 'medium', value: translate('Medium') }, key: 'small',
{ key: 'large', value: translate('Large') } get value() {
return translate('Small');
}
},
{
key: 'medium',
get value() {
return translate('Medium');
}
},
{
key: 'large',
get value() {
return translate('Large');
}
}
]; ];
class DiscoverMoviePosterOptionsModalContent extends Component { class DiscoverMoviePosterOptionsModalContent extends Component {
@@ -39,6 +39,12 @@
flex: 0 0 90px; flex: 0 0 90px;
} }
.popularity {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
flex: 0 0 100px;
}
.lists { .lists {
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css'; composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
@@ -11,6 +11,7 @@ interface CssExports {
'lists': string; 'lists': string;
'originalLanguage': string; 'originalLanguage': string;
'physicalRelease': string; 'physicalRelease': string;
'popularity': string;
'ratings': string; 'ratings': string;
'runtime': string; 'runtime': string;
'sortTitle': string; 'sortTitle': string;
@@ -64,6 +64,12 @@
flex: 0 0 90px; flex: 0 0 90px;
} }
.popularity {
composes: cell;
flex: 0 0 100px;
}
.lists { .lists {
composes: cell; composes: cell;
@@ -16,6 +16,7 @@ interface CssExports {
'lists': string; 'lists': string;
'originalLanguage': string; 'originalLanguage': string;
'physicalRelease': string; 'physicalRelease': string;
'popularity': string;
'ratings': string; 'ratings': string;
'runtime': string; 'runtime': string;
'sortTitle': string; 'sortTitle': string;
@@ -13,6 +13,7 @@ import AddNewDiscoverMovieModal from 'DiscoverMovie/AddNewDiscoverMovieModal';
import ExcludeMovieModal from 'DiscoverMovie/Exclusion/ExcludeMovieModal'; import ExcludeMovieModal from 'DiscoverMovie/Exclusion/ExcludeMovieModal';
import { icons } from 'Helpers/Props'; import { icons } from 'Helpers/Props';
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks'; import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
import MoviePopularityIndex from 'Movie/MoviePopularityIndex';
import formatRuntime from 'Utilities/Date/formatRuntime'; import formatRuntime from 'Utilities/Date/formatRuntime';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import ListMovieStatusCell from './ListMovieStatusCell'; import ListMovieStatusCell from './ListMovieStatusCell';
@@ -73,6 +74,7 @@ class DiscoverMovieRow extends Component {
images, images,
genres, genres,
ratings, ratings,
popularity,
certification, certification,
collection, collection,
columns, 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') { if (name === 'certification') {
return ( return (
<VirtualTableRowCell <VirtualTableRowCell
@@ -384,6 +394,7 @@ DiscoverMovieRow.propTypes = {
runtime: PropTypes.number, runtime: PropTypes.number,
genres: PropTypes.arrayOf(PropTypes.string).isRequired, genres: PropTypes.arrayOf(PropTypes.string).isRequired,
ratings: PropTypes.object.isRequired, ratings: PropTypes.object.isRequired,
popularity: PropTypes.number.isRequired,
certification: PropTypes.string, certification: PropTypes.string,
collection: PropTypes.object, collection: PropTypes.object,
columns: PropTypes.arrayOf(PropTypes.object).isRequired, columns: PropTypes.arrayOf(PropTypes.object).isRequired,
+4
View File
@@ -34,6 +34,7 @@ import {
faBug as fasBug, faBug as fasBug,
faBuilding as fasBuilding, faBuilding as fasBuilding,
faBullhorn as fasBullhorn, faBullhorn as fasBullhorn,
faCalculator as fasCalculator,
faCalendarAlt as fasCalendarAlt, faCalendarAlt as fasCalendarAlt,
faCaretDown as fasCaretDown, faCaretDown as fasCaretDown,
faCheck as fasCheck, faCheck as fasCheck,
@@ -61,6 +62,7 @@ import {
faFileInvoice as farFileInvoice, faFileInvoice as farFileInvoice,
faFilm as fasFilm, faFilm as fasFilm,
faFilter as fasFilter, faFilter as fasFilter,
faFire as fasFire,
faFlag as fasFlag, faFlag as fasFlag,
faFolderOpen as fasFolderOpen, faFolderOpen as fasFolderOpen,
faForward as fasForward, faForward as fasForward,
@@ -188,10 +190,12 @@ export const PAGE_PREVIOUS = fasBackward;
export const PAGE_NEXT = fasForward; export const PAGE_NEXT = fasForward;
export const PAGE_LAST = fasFastForward; export const PAGE_LAST = fasFastForward;
export const PARENT = fasLevelUpAlt; export const PARENT = fasLevelUpAlt;
export const PARSE = fasCalculator;
export const PAUSED = fasPause; export const PAUSED = fasPause;
export const PENDING = farClock; export const PENDING = farClock;
export const PLAY = fasPlay; export const PLAY = fasPlay;
export const PROFILE = fasUser; export const PROFILE = fasUser;
export const POPULAR = fasFire;
export const POSTER = fasTh; export const POSTER = fasTh;
export const QUEUED = fasCloud; export const QUEUED = fasCloud;
export const QUICK = fasRocket; export const QUICK = fasRocket;
@@ -25,11 +25,15 @@ import styles from './InteractiveImportSelectFolderModalContent.css';
const recentFoldersColumns = [ const recentFoldersColumns = [
{ {
name: 'folder', name: 'folder',
label: translate('Folder'), get label() {
return translate('Folder');
},
}, },
{ {
name: 'lastUsed', name: 'lastUsed',
label: translate('LastUsed'), get label() {
return translate('LastUsed');
},
}, },
{ {
name: 'actions', name: 'actions',
@@ -71,36 +71,48 @@ type OnSelectedChangeCallback = React.ComponentProps<
const COLUMNS = [ const COLUMNS = [
{ {
name: 'relativePath', name: 'relativePath',
label: translate('RelativePath'), get label() {
return translate('RelativePath');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'movie', name: 'movie',
label: translate('Movie'), get label() {
return translate('Movie');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'releaseGroup', name: 'releaseGroup',
label: translate('ReleaseGroup'), get label() {
return translate('ReleaseGroup');
},
isVisible: true, isVisible: true,
}, },
{ {
name: 'quality', name: 'quality',
label: translate('Quality'), get label() {
return translate('Quality');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'languages', name: 'languages',
label: translate('Languages'), get label() {
return translate('Languages');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
{ {
name: 'size', name: 'size',
label: translate('Size'), get label() {
return translate('Size');
},
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
}, },
@@ -108,7 +120,7 @@ const COLUMNS = [
name: 'customFormats', name: 'customFormats',
label: React.createElement(Icon, { label: React.createElement(Icon, {
name: icons.INTERACTIVE, name: icons.INTERACTIVE,
title: translate('CustomFormat'), title: () => translate('CustomFormat'),
}), }),
isSortable: true, isSortable: true,
isVisible: true, isVisible: true,
@@ -127,11 +139,23 @@ const COLUMNS = [
const importModeOptions = [ const importModeOptions = [
{ {
key: 'chooseImportMode', key: 'chooseImportMode',
value: translate('ChooseImportMode'), get value() {
return translate('ChooseImportMode');
},
disabled: true, disabled: true,
}, },
{ key: 'move', value: translate('MoveFiles') }, {
{ key: 'copy', value: translate('HardlinkCopyFiles') }, key: 'move',
get value() {
return translate('MoveFiles');
},
},
{
key: 'copy',
get value() {
return translate('HardlinkCopyFiles');
},
},
]; ];
function isSameMovieFile( function isSameMovieFile(
@@ -25,6 +25,7 @@ import {
import { SelectStateInputProps } from 'typings/props'; import { SelectStateInputProps } from 'typings/props';
import Rejection from 'typings/Rejection'; import Rejection from 'typings/Rejection';
import formatBytes from 'Utilities/Number/formatBytes'; import formatBytes from 'Utilities/Number/formatBytes';
import formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder'; import InteractiveImportRowCellPlaceholder from './InteractiveImportRowCellPlaceholder';
import styles from './InteractiveImportRow.css'; import styles from './InteractiveImportRow.css';
@@ -45,6 +46,7 @@ interface InteractiveImportRowProps {
languages?: Language[]; languages?: Language[];
size: number; size: number;
customFormats?: object[]; customFormats?: object[];
customFormatScore?: number;
rejections: Rejection[]; rejections: Rejection[];
columns: Column[]; columns: Column[];
movieFileId?: number; movieFileId?: number;
@@ -66,6 +68,7 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
releaseGroup, releaseGroup,
size, size,
customFormats, customFormats,
customFormatScore,
rejections, rejections,
isSelected, isSelected,
modalTitle, modalTitle,
@@ -293,8 +296,11 @@ function InteractiveImportRow(props: InteractiveImportRowProps) {
<TableRowCell> <TableRowCell>
{customFormats?.length ? ( {customFormats?.length ? (
<Popover <Popover
anchor={<Icon name={icons.INTERACTIVE} />} anchor={formatCustomFormatScore(
title={translate('Formats')} customFormatScore,
customFormats.length
)}
title={translate('CustomFormats')}
body={ body={
<div className={styles.customFormatTooltip}> <div className={styles.customFormatTooltip}>
<MovieFormats formats={customFormats} /> <MovieFormats formats={customFormats} />
@@ -29,22 +29,30 @@ import styles from './SelectMovieModalContent.css';
const columns = [ const columns = [
{ {
name: 'title', name: 'title',
label: translate('Title'), get label() {
return translate('Title');
},
isVisible: true, isVisible: true,
}, },
{ {
name: 'year', name: 'year',
label: translate('Year'), get label() {
return translate('Year');
},
isVisible: true, isVisible: true,
}, },
{ {
name: 'imdbId', name: 'imdbId',
label: translate('ImdbId'), get label() {
return translate('ImdbId');
},
isVisible: true, isVisible: true,
}, },
{ {
name: 'tmdbId', name: 'tmdbId',
label: translate('TmdbId'), get label() {
return translate('TmdbId');
},
isVisible: true, isVisible: true,
}, },
]; ];
@@ -4,12 +4,8 @@
margin-bottom: 10px; margin-bottom: 10px;
} }
.filteredMessage { .alert {
composes: alert from '~Components/Alert.css';
margin-top: 10px; margin-top: 10px;
} }
.blankpad {
padding-top: 10px;
padding-bottom: 10px;
padding-left: 2em;
}
@@ -1,9 +1,8 @@
// This file is automatically generated. // This file is automatically generated.
// Please do not change this file! // Please do not change this file!
interface CssExports { interface CssExports {
'blankpad': string; 'alert': string;
'filterMenuContainer': string; 'filterMenuContainer': string;
'filteredMessage': string;
} }
export const cssExports: CssExports; export const cssExports: CssExports;
export default cssExports; export default cssExports;
@@ -1,10 +1,11 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Alert from 'Components/Alert';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Table from 'Components/Table/Table'; import Table from 'Components/Table/Table';
import TableBody from 'Components/Table/TableBody'; import TableBody from 'Components/Table/TableBody';
import { icons, sortDirections } from 'Helpers/Props'; import { icons, kinds, sortDirections } from 'Helpers/Props';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
import InteractiveSearchRowConnector from './InteractiveSearchRowConnector'; import InteractiveSearchRowConnector from './InteractiveSearchRowConnector';
import styles from './InteractiveSearchContent.css'; import styles from './InteractiveSearchContent.css';
@@ -12,13 +13,17 @@ import styles from './InteractiveSearchContent.css';
const columns = [ const columns = [
{ {
name: 'protocol', name: 'protocol',
label: translate('Source'), get label() {
return translate('Source');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'age', name: 'age',
label: translate('Age'), get label() {
return translate('Age');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
@@ -38,50 +43,66 @@ const columns = [
}, },
{ {
name: 'title', name: 'title',
label: translate('Title'), get label() {
return translate('Title');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'indexer', name: 'indexer',
label: translate('Indexer'), get label() {
return translate('Indexer');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'history', name: 'history',
label: translate('History'), get label() {
return translate('History');
},
isSortable: true, isSortable: true,
fixedSortDirection: sortDirections.ASCENDING, fixedSortDirection: sortDirections.ASCENDING,
isVisible: true isVisible: true
}, },
{ {
name: 'size', name: 'size',
label: translate('Size'), get label() {
return translate('Size');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'peers', name: 'peers',
label: translate('Peers'), get label() {
return translate('Peers');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'languages', name: 'languages',
label: translate('Language'), get label() {
return translate('Language');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'qualityWeight', name: 'qualityWeight',
label: translate('Quality'), get label() {
return translate('Quality');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
{ {
name: 'customFormat', name: 'customFormat',
label: translate('Formats'), get label() {
return translate('Formats');
},
isSortable: true, isSortable: true,
isVisible: true isVisible: true
}, },
@@ -89,7 +110,7 @@ const columns = [
name: 'customFormatScore', name: 'customFormatScore',
label: React.createElement(Icon, { label: React.createElement(Icon, {
name: icons.SCORE, name: icons.SCORE,
title: translate('CustomFormatScore') title: () => translate('CustomFormatScore')
}), }),
isSortable: true, isSortable: true,
isVisible: true isVisible: true
@@ -127,23 +148,23 @@ function InteractiveSearchContent(props) {
{ {
!isFetching && !!error && !isFetching && !!error &&
<div className={styles.blankpad}> <Alert kind={kinds.DANGER} className={styles.alert}>
{translate('UnableToLoadResultsIntSearch')} {translate('UnableToLoadResultsIntSearch')}
</div> </Alert>
} }
{ {
!isFetching && isPopulated && !totalReleasesCount && !isFetching && isPopulated && !totalReleasesCount &&
<div className={styles.blankpad}> <Alert kind={kinds.INFO} className={styles.alert}>
{translate('NoResultsFound')} {translate('NoResultsFound')}
</div> </Alert>
} }
{ {
!!totalReleasesCount && isPopulated && !items.length && !!totalReleasesCount && isPopulated && !items.length &&
<div className={styles.blankpad}> <Alert kind={kinds.WARNING} className={styles.alert}>
{translate('AllResultsHiddenFilter')} {translate('AllResultsHiddenFilter')}
</div> </Alert>
} }
{ {
@@ -175,9 +196,9 @@ function InteractiveSearchContent(props) {
{ {
totalReleasesCount !== items.length && !!items.length && totalReleasesCount !== items.length && !!items.length &&
<div className={styles.filteredMessage}> <Alert kind={kinds.INFO} className={styles.alert}>
{translate('SomeResultsHiddenFilter')} {translate('SomeResultsHiddenFilter')}
</div> </Alert>
} }
</div> </div>
); );
@@ -31,6 +31,7 @@ function createMapDispatchToProps(dispatch, props) {
dispatch( dispatch(
deleteMovie({ deleteMovie({
id: props.movieId, id: props.movieId,
collectionTmdbId: this.collection?.tmdbId,
deleteFiles, deleteFiles,
addImportExclusion addImportExclusion
}) })
@@ -10,17 +10,23 @@ import styles from './MovieTitlesTableContent.css';
const columns = [ const columns = [
{ {
name: 'altTitle', name: 'altTitle',
label: translate('AlternativeTitle'), get label() {
return translate('AlternativeTitle');
},
isVisible: true isVisible: true
}, },
{ {
name: 'language', name: 'language',
label: translate('Language'), get label() {
return translate('Language');
},
isVisible: true isVisible: true
}, },
{ {
name: 'sourceType', name: 'sourceType',
label: translate('Type'), get label() {
return translate('Type');
},
isVisible: true isVisible: true
} }
]; ];
@@ -3,3 +3,9 @@
margin-right: auto; margin-right: auto;
} }
.tagInternalInput {
composes: internalInput from '~Components/Form/TagInput.css';
flex: 0 0 100%;
}

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