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

Compare commits

..

89 Commits

Author SHA1 Message Date
Qstick 17c6d11a47 fixup! New: Multiple Quality Profiles and Files Per Movie 2022-12-04 23:43:41 +00:00
ta264 a994502e59 Add api endpoint to generate the required login cookie
(cherry picked from commit 4180e2787a1ad5284873de4847f345b2c47df72a)
2022-12-04 23:43:41 +00:00
ta264 4154414adf Add OIDC and Plex authentication methods
(cherry picked from commit 3ff3de6b90704fba266833115cd9d03ace99aae9)
2022-12-04 23:43:41 +00:00
ta264 c5b12d074e Add explicit ApiKey requirement for ApiKey auth
(cherry picked from commit 8a3a998243e888e8f27c609f4bace5b42ad7ec50)
2022-12-04 13:06:25 -06:00
Qstick 578aa14770 Cleanup Translation Implementation in UI 2022-12-04 13:06:25 -06:00
Mark McDowall da1bc0aa88 New: Calendar option for full color events
(cherry picked from commit 0210b5c5c1b5c56dce6f4c9f3f56366adba950d3)

Fixup Calendar for Full Color View, Final CSS fixups

Update localization
2022-12-04 13:06:25 -06:00
Qstick a56d827744 Bump SQLite to 3.38.5 (1.0.116) 2022-12-04 13:06:25 -06:00
Qstick a53234a107 Bump FFMpeg to 5.1.2 2022-12-04 13:06:24 -06:00
Marty Zalega a015fa3255 Don't lowercase UrlBase in ConfigFileProvider
UrlBase should honour the case it is given.

(cherry picked from commit e1de523c89f7649e64f520b090bbdb2f56cc4b85)
2022-12-04 13:06:24 -06:00
Qstick b2cb95829c New: Rework Movie Details view 2022-12-04 13:06:24 -06:00
Mark McDowall 64fd60a7d5 New: Migrate user passwords to Pbkdf2
(cherry picked from commit 269e72a2193b584476bec338ef41e6fb2e5cbea6)
2022-12-04 13:06:24 -06:00
Qstick c3368d9e6c New: v4 API (DROP v3 AFTER TESTING PERIOD) 2022-12-04 13:06:20 -06:00
Qstick 583c5d501c Build Branch [REVERT] 2022-12-04 13:05:10 -06:00
Qstick af6b16ec57 New: Multiple Quality Profiles and Files Per Movie 2022-12-04 13:05:05 -06:00
Qstick 7ac5a5843b New: Rework and Require Authentication
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-12-04 13:04:33 -06:00
Qstick 2465815890 Bump Version to 5 2022-12-04 13:04:33 -06:00
Weblate c0caf65b69 Translated using Weblate (Dutch) [skip ci]
Currently translated at 95.2% (1100 of 1155 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1155 of 1155 strings)

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

Currently translated at 100.0% (1155 of 1155 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Robin Flikkema <robin@robinflikkema.nl>
Co-authored-by: Weblate <noreply@weblate.org>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2022-12-02 21:13:27 -06:00
Davo1624 cd889872de Properly parse H.265 4k as 4k quality (#7812)
* Update en.json

* Properly parse H265 for 4k quality

`.WEB-DL.4K.H265.AAC` parses properly for 4k quality
`.WEB-DL.4K.H.265.AAC` parses improperly as 480p
2022-11-29 22:00:36 -06:00
Servarr 6366e335bc Automated API Docs update 2022-11-29 21:57:01 -06:00
Qstick 41f10d098e Don't block task queue for queued update task when there are longer running tasks
Fixes #7538

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-11-29 21:44:03 -06:00
Qstick b2c1698097 Fixed: False Positive HC in some cases
Fixes #7785
2022-11-29 20:52:23 -06:00
Mark McDowall ed20487f30 Fixed: Handle Flood reporting errors for completed and stopped downloads
(cherry picked from commit f2b2eb69a3e8b271535bd92dc2f5cbfd45664daf)
2022-11-28 21:25:34 -06:00
Bruno Garcia d1235adfc4 Sentry SDK v3.23.1
Co-authored-by: Bruno Garcia <bruno@Brunos-MacBook-Pro.local>
(cherry picked from commit de3cb07c57d762084c983336aa01b761a8e4b74a)
2022-11-28 21:30:06 +00:00
Qstick 561993e30c Fixed: Parse multiple languages for two letter cases
Fixes #7783
2022-11-25 19:16:29 -06:00
Weblate 14f8f89634 Translated using Weblate (Czech) [skip ci]
Currently translated at 90.9% (1051 of 1155 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1155 of 1155 strings)

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

Currently translated at 100.0% (1155 of 1155 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1155 of 1155 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: Zalhera <tobias.bechen@gmail.com>
Co-authored-by: marapavelka <mara.pavelka@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/cs/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2022-11-24 18:40:38 -06:00
Qstick 874482dbce Webhook IndexerFlags to string list 2022-11-23 19:41:38 -06:00
Qstick bae374c0c8 Additional Fields in Webhooks 2022-11-23 18:42:04 -06:00
Qstick 4f5ad899bb Fix Collection adding log 2022-11-23 18:31:48 -06:00
Qstick adcd00d9fd Convert Notifiarr Payload to JSON, Standardize with Webhook 2022-11-22 21:17:25 -06:00
Servarr d70d351ea2 Automated API Docs update 2022-11-22 19:25:54 -06:00
Qstick ef90ac7041 Add theme property in API
Fixes #7772
2022-11-22 18:27:47 -06:00
Mark McDowall aa8e886dab Added SECURITY.md
(cherry picked from commit 80af164385d9087a627142ca2281ae74ac0572af)

[common]
2022-11-21 19:23:43 -06:00
Mark McDowall c7ee2c9166 Publish ApplicationStartingEvent during startup
(cherry picked from commit 5400bce1295bdc4198d2cfe0b9258bbb7ccf0852)
2022-11-21 18:47:59 -06:00
Robin Dadswell 5330815e1b fixup: some tests for log files 2022-11-21 18:42:38 -06:00
Qstick 296ec6c565 Fixup WindowsApp.cs 2022-11-20 15:08:26 -06:00
Qstick bf89995984 Fixup SysTrayApp.cs 2022-11-20 13:09:42 -06:00
Qstick 44d7c54077 Enforce comment style in CS 2022-11-20 12:27:45 -06:00
Qstick d37fac5343 Add PreSubstitutionRegex Capabilities
Fixes #7389
2022-11-20 12:20:50 -06:00
Qstick ae8245c3c5 New: Reset Quality Definitions to default
(cherry picked from commit d5fff15f32fdb49768dcadd94c760678e650c884)
2022-11-20 12:20:50 -06:00
Qstick 850bfdcf82 New: Native Theme Engine
Co-Authored-By: Zak Saunders <1936903+thezak48@users.noreply.github.com>
2022-11-20 11:49:50 -06:00
Qstick 7d4865dea3 Fixed: Close all database connections on shutdown 2022-11-20 11:47:28 -06:00
Weblate f9ef7e3578 Translated using Weblate (Dutch) [skip ci]
Currently translated at 94.7% (1088 of 1148 strings)

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

Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 99.9% (1147 of 1148 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (German) [skip ci]

Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (French) [skip ci]

Currently translated at 98.4% (1130 of 1148 strings)

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

Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (Catalan) [skip ci]

Currently translated at 100.0% (1148 of 1148 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Havok Dan <havokdan@yahoo.com.br>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Sylvain Place <sylvain.place@etud.univ-jfc.fr>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: dtalens <databio@gmail.com>
Co-authored-by: reloxx <reloxx@interia.pl>
Co-authored-by: wauterr <wouter.rijken@gmail.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/ca/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/de/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/nl/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/pt_BR/
Translation: Servarr/Radarr
2022-11-20 09:28:34 -06:00
Qstick fb25422922 Fix test error due to DryIOC update 2022-11-19 16:59:53 -06:00
Mark McDowall ac3d4bee35 Improve page scrollbar
New: Style scrollbar in Firefox
Fixed: Scrolling with click and drag

(cherry picked from commit 9bd783d49c91600d6575fc86e7bdd56858c213f1)
2022-11-19 16:31:37 -06:00
Mark McDowall bb60510515 Added react-hooks lint rules
(cherry picked from commit 381d64259396582de8d63ada99333e42cf5e3189)
2022-11-19 16:30:16 -06:00
Qstick 5c9e11d7a0 Bump DryIoc to 5.3.0 2022-11-19 16:23:36 -06:00
Mark McDowall 6c01e8c91f Fixed: Testing SABnzbd when no categories are configured
(cherry picked from commit 0e31281828c737e3f6eecbb870960194888a970a)
2022-11-14 08:56:52 +00:00
Servarr 488a7d183e Automated API Docs update 2022-11-12 21:38:28 -06:00
Qstick 7fcb0d6e45 New: Base API info endpoint
(cherry picked from commit 5e57ffbcf9ac3a346d4bf2b692248393215bad89)
2022-11-12 19:56:41 -06:00
Jayson Reis bd19c89f6e chore: Chain exceptions when trying to get rss's item size 2022-11-07 19:21:09 -06:00
Qstick 15e5ad5f84 Revert: Bump FFMpeg 2022-11-05 08:08:30 -05:00
Qstick 1732e23945 Fixed: Prevent Media Info error if no tags exist 2022-11-04 20:17:54 -05:00
ta264 5a7a9db7ed Bump FFprobe 2022-11-04 10:33:45 -05:00
Qstick 182cda47b0 Fixed: Detect 3D in some video files 2022-11-03 23:41:35 -05:00
Qstick 294d95fae4 Create CODE_OF_CONDUCT.md 2022-11-03 15:56:41 -05:00
Davo1624 0e3f871e0e Clarify quality profile wording (#7714)
[common]
2022-11-03 13:23:35 -05:00
ta264 b0f5f02edc Use wildcard for FreeBSD itemPattern 2022-11-02 21:20:58 +00:00
Qstick 2afe6af5a6 Ignore brotli test on osx
[common]
2022-10-30 19:02:27 -05:00
Weblate e2eaf91aa7 Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (Finnish) [skip ci]

Currently translated at 100.0% (1148 of 1148 strings)

Translated using Weblate (Hungarian) [skip ci]

Currently translated at 100.0% (1148 of 1148 strings)

Update translation files  [skip ci]

Updated by "Remove blank strings" hook in Weblate.

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

Currently translated at 99.9% (1146 of 1147 strings)

Co-authored-by: Csaba <csab0825@gmail.com>
Co-authored-by: Oskari Lavinto <olavinto@protonmail.com>
Co-authored-by: Sincejunly <qq943384135@gmail.com>
Co-authored-by: Weblate <noreply@weblate.org>
Co-authored-by: libsu <libsu@qq.com>
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/fi/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/hu/
Translate-URL: https://translate.servarr.com/projects/servarr/radarr/zh_CN/
Translation: Servarr/Radarr
2022-10-23 10:17:56 -05:00
Qstick 0e1c2c3c50 Bump moment to 2.29.4 2022-10-19 21:54:56 -05:00
Qstick 69cf2e89a6 Fixed: WEB-Rip parsed as WebDL
Fixes #7424
Fixes #7463

Co-Authored-By: bakerboy448 <55419169+bakerboy448@users.noreply.github.com>
2022-10-19 21:46:24 -05:00
Mark McDowall 9830230589 New: Auto focus input when editing release group during manual import
Closes #7075

(cherry picked from commit 715711e6d718a79744dd4ec2eb570f8d0732de3b)
2022-10-19 21:16:36 -05:00
Kevin Richter b1f0b2c216 Fixed: Improve moving file to location where another one exists
Fixes #7460

(cherry picked from commit 8ab040f612ee04dac4813a08cdeaddd446a64dc9)
2022-10-19 21:12:33 -05:00
Mark McDowall 7c6858ecfb New: Rename Protocol to Preferred Protocol in Delay Profiles
Closes #7278

(cherry picked from commit 704cf7aebef60b5b5bdf1ea55d68d4a3394396e0)
2022-10-19 21:03:23 -05:00
Qstick ee32d42c94 New: Parse Spanish language using Español
Fixes #7252
2022-10-19 20:58:12 -05:00
Qstick 3390df4085 New: Parse anime version with a space before 'v'
Closes #7633
2022-10-19 20:50:02 -05:00
Qstick 01bc5f6fc8 New: Include MediaInfo / CF for Webhooks
Fixes #7680

(cherry picked from commit 47116ea6637c4bcb3365f6882bfd02ea74bf687e)
2022-10-19 20:33:40 -05:00
Dtaggart 2d867a6cb6 New: Add indexer name to the download report log
Fixes #7686

(cherry picked from commit 00d467314b0e206742d4aff5aa20563e79b2ec55)
2022-10-19 20:33:40 -05:00
Qstick 411f8866ec Fixed: Handle rename when video has no audio tracks
Fixes #7648
2022-10-19 20:07:45 -05:00
Mark McDowall 5316382113 New: Natural Sorting Manual Import Relative Paths
(cherry picked from commit bdd5865876796bc203c8117418a5389afc8b5f11)
2022-10-18 21:31:07 -05:00
Mark McDowall 8fe81b428a Fixed: Ping plex.tv to keep auth token active
(cherry picked from commit 93bd8543b158c952b50e56d4339e4a3c699770b0)
2022-10-18 21:31:07 -05:00
Mark McDowall 43a2a2d335 Fixed: Plex Library Updates
(cherry picked from commit bd70fa54107c225ea08da53183e2be944e730475)
2022-10-18 21:31:07 -05:00
Qstick 5c8b58c30d New: Parse more BDRemux release names
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Qstick 131a223bb9 New: Parse more WEB release names
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Bakerboy448 dfaab639bf New: Include MediaInfo for CustomScripts OnDownload
(cherry picked from commit 77a7f3ef4f4762c45813fa94212ab9976e84f6f8)
2022-10-18 20:13:29 -05:00
Stevie Robinson c7be63d48f Fixed: updated rTorrent download client note
(cherry picked from commit 743d28b93a55553ee25381570d0daa04ed2117af)
2022-10-18 20:13:29 -05:00
Qstick 2958faf4a8 Add import date to upgraded episodes in CustomScript and Webhook connections
Fixes #7547

Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Qstick 4280df8b61 Fixed: Better error messaging if you try to import an invalid Custom Format
Co-Authored-By: Robert Dailey <1768054+rcdailey@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Qstick 1f91be6407 Fixed: Fall back to sorting by release title if series is not matched
Co-Authored-By: Mark McDowall <markus101@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Chromo-residuum-opec eb43a3c2d0 Update help text for rTorrent download client options
(cherry picked from commit d2a23f7bcdf71800f019644d7b6b5d712e311d7f)
2022-10-18 20:13:29 -05:00
Qstick 20c7e84676 New: Use filename without extension if SceneName is unavailable
Fixe #6639
2022-10-18 20:13:29 -05:00
Mark McDowall 691a8955fe Fixed: Parsing similar movie titles with common words at end 2022-10-18 20:13:29 -05:00
Qstick 53a9c849cb New: CustomFormat Score for history grabs
Fixes #5892
Fixes #5893
2022-10-18 20:13:29 -05:00
Qstick 856a55a9c9 New: Added advanced subtitle/audio language filter to {MediaInfo ..}
Fixes #4710

Co-Authored-By: Taloth <Taloth@users.noreply.github.com>
2022-10-18 20:13:29 -05:00
Qstick 43cd536746 Throw on search error
Fixes #4690
2022-10-18 20:13:29 -05:00
Qstick 4a205d8041 Add thread to discord notification [common] 2022-10-16 23:23:13 -05:00
Qstick 2525ac2d1a Bump version to 4.3.1 2022-10-16 21:14:07 -05:00
psylenced e5ceb20a83 Fixed: Discord webhook logs now get cleansed to remove webhook id and token. 2022-10-16 09:55:22 -05:00
Qstick 0f6b11f55d Cleanup Dual Target and Mono References 2022-10-15 21:01:37 -05:00
840 changed files with 28996 additions and 3902 deletions
-1
View File
@@ -42,7 +42,6 @@ csharp_style_var_elsewhere = true:suggestion
# Stylecop Rules # Stylecop Rules
dotnet_diagnostic.SA0001.severity = none dotnet_diagnostic.SA0001.severity = none
dotnet_diagnostic.SA1005.severity = none
dotnet_diagnostic.SA1025.severity = none dotnet_diagnostic.SA1025.severity = none
dotnet_diagnostic.SA1101.severity = none dotnet_diagnostic.SA1101.severity = none
dotnet_diagnostic.SA1116.severity = none dotnet_diagnostic.SA1116.severity = none
+132
View File
@@ -0,0 +1,132 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<development@radarr.video>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations
+8
View File
@@ -0,0 +1,8 @@
# Security Policy
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities on Discord (preferred) to
any of the Servarr Dev role holders (red names) or via email: development@servarr.com. You will receive a response from
us within 72 hours. If the issue is confirmed, we will release a patch as soon
as possible depending on complexity/severity.
+5 -3
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.3.0' majorVersion: '5.0.0'
minorVersion: $[counter('minorVersion', 2000)] minorVersion: $[counter('minorVersion', 2000)]
radarrVersion: '$(majorVersion).$(minorVersion)' radarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(radarrVersion)' buildName: '$(Build.SourceBranchName).$(radarrVersion)'
@@ -27,6 +27,7 @@ trigger:
include: include:
- develop - develop
- master - master
- zeus
pr: pr:
branches: branches:
@@ -761,7 +762,7 @@ stages:
inputs: inputs:
buildType: 'current' buildType: 'current'
artifactName: Packages artifactName: Packages
itemPattern: '/$(pattern)' itemPattern: '**/$(pattern)'
targetPath: $(Build.ArtifactStagingDirectory) targetPath: $(Build.ArtifactStagingDirectory)
- bash: | - bash: |
mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
@@ -1092,7 +1093,7 @@ stages:
projectVersion: '$(radarrVersion)' projectVersion: '$(radarrVersion)'
extraProperties: | extraProperties: |
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/** sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
sonar.coverage.exclusions=**/Radarr.Api.V3/**/* sonar.coverage.exclusions=**/Radarr.Api.V*/**/*
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
- bash: | - bash: |
@@ -1143,4 +1144,5 @@ stages:
SYSTEM_ACCESSTOKEN: $(System.AccessToken) SYSTEM_ACCESSTOKEN: $(System.AccessToken)
DISCORDCHANNELID: $(discordChannelId) DISCORDCHANNELID: $(discordChannelId)
DISCORDWEBHOOKKEY: $(discordWebhookKey) DISCORDWEBHOOKKEY: $(discordWebhookKey)
DISCORDTHREADID: $(discordThreadId)
+1 -1
View File
@@ -29,7 +29,7 @@ dotnet msbuild -restore $slnFile -p:Configuration=Debug -p:Platform=$platform -p
dotnet new tool-manifest dotnet new tool-manifest
dotnet tool install --version 6.3.0 Swashbuckle.AspNetCore.Cli dotnet tool install --version 6.3.0 Swashbuckle.AspNetCore.Cli
dotnet tool run swagger tofile --output ./src/Radarr.Api.V3/openapi.json "$outputFolder/net6.0/$RUNTIME/radarr.console.dll" v3 & dotnet tool run swagger tofile --output ./src/Radarr.Api.V4/openapi.json "$outputFolder/net6.0/$RUNTIME/radarr.console.dll" v4 &
sleep 45 sleep 45
+4 -1
View File
@@ -39,6 +39,7 @@ module.exports = {
plugins: [ plugins: [
'filenames', 'filenames',
'react', 'react',
'react-hooks',
'simple-import-sort', 'simple-import-sort',
'import' 'import'
], ],
@@ -308,7 +309,9 @@ module.exports = {
'react/react-in-jsx-scope': 2, 'react/react-in-jsx-scope': 2,
'react/self-closing-comp': 2, 'react/self-closing-comp': 2,
'react/sort-comp': 2, 'react/sort-comp': 2,
'react/jsx-wrap-multilines': 2 'react/jsx-wrap-multilines': 2,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error'
}, },
overrides: [ overrides: [
{ {
+1 -2
View File
@@ -1,7 +1,6 @@
const reload = require('require-nocache')(module); const reload = require('require-nocache')(module);
const cssVarsFiles = [ const cssVarsFiles = [
'./src/Styles/Variables/colors',
'./src/Styles/Variables/dimensions', './src/Styles/Variables/dimensions',
'./src/Styles/Variables/fonts', './src/Styles/Variables/fonts',
'./src/Styles/Variables/animations', './src/Styles/Variables/animations',
@@ -29,4 +28,4 @@ module.exports = {
'postcss-color-function', 'postcss-color-function',
'postcss-nested' 'postcss-nested'
] ]
}; };
@@ -10,6 +10,12 @@
width: 80px; width: 80px;
} }
.customFormatScore {
composes: cell from '~Components/Table/Cells/TableRowCell.css';
width: 55px;
}
.releaseGroup { .releaseGroup {
composes: cell from '~Components/Table/Cells/TableRowCell.css'; composes: cell from '~Components/Table/Cells/TableRowCell.css';
@@ -9,6 +9,7 @@ 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 formatCustomFormatScore from 'Utilities/Number/formatCustomFormatScore';
import HistoryDetailsModal from './Details/HistoryDetailsModal'; import HistoryDetailsModal from './Details/HistoryDetailsModal';
import HistoryEventTypeCell from './HistoryEventTypeCell'; import HistoryEventTypeCell from './HistoryEventTypeCell';
import styles from './HistoryRow.css'; import styles from './HistoryRow.css';
@@ -168,6 +169,17 @@ class HistoryRow extends Component {
); );
} }
if (name === 'customFormatScore') {
return (
<TableRowCell
key={name}
className={styles.customFormatScore}
>
{formatCustomFormatScore(data.customFormatScore)}
</TableRowCell>
);
}
if (name === 'releaseGroup') { if (name === 'releaseGroup') {
return ( return (
<TableRowCell <TableRowCell
@@ -1,13 +1,13 @@
.torrent { .torrent {
composes: label from '~Components/Label.css'; composes: label from '~Components/Label.css';
border-color: $torrentColor; border-color: var(--torrentColor);
background-color: $torrentColor; background-color: var(--torrentColor);
} }
.usenet { .usenet {
composes: label from '~Components/Label.css'; composes: label from '~Components/Label.css';
border-color: $usenetColor; border-color: var(--usenetColor);
background-color: $usenetColor; background-color: var(--usenetColor);
} }
@@ -6,12 +6,12 @@
.searchIconContainer { .searchIconContainer {
width: 58px; width: 58px;
height: 46px; height: 46px;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-right: none; border-right: none;
border-radius: 4px; border-radius: 4px;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
background-color: #edf1f2; background-color: var(--searchIconContainerBackgroundColor);
text-align: center; text-align: center;
line-height: 46px; line-height: 46px;
} }
@@ -25,7 +25,7 @@
} }
.clearLookupButton { .clearLookupButton {
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-left: none; border-left: none;
border-top-right-radius: 4px; border-top-right-radius: 4px;
border-bottom-right-radius: 4px; border-bottom-right-radius: 4px;
@@ -4,7 +4,7 @@
.year { .year {
margin-left: 5px; margin-left: 5px;
color: $disabledColor; color: var(--disabledColor);
} }
.poster { .poster {
@@ -20,10 +20,6 @@ class AddNewMovieModalContent extends Component {
// //
// Listeners // Listeners
onQualityProfileIdChange = ({ value }) => {
this.props.onInputChange({ name: 'qualityProfileId', value: parseInt(value) });
};
onAddMoviePress = () => { onAddMoviePress = () => {
this.props.onAddMoviePress(); this.props.onAddMoviePress();
}; };
@@ -40,7 +36,7 @@ class AddNewMovieModalContent extends Component {
isAdding, isAdding,
rootFolderPath, rootFolderPath,
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
searchForMovie, searchForMovie,
folder, folder,
@@ -130,9 +126,9 @@ class AddNewMovieModalContent extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileIds"
onChange={this.onQualityProfileIdChange} onChange={onInputChange}
{...qualityProfileId} {...qualityProfileIds}
/> />
</FormGroup> </FormGroup>
@@ -189,7 +185,7 @@ AddNewMovieModalContent.propTypes = {
addError: PropTypes.object, addError: PropTypes.object,
rootFolderPath: PropTypes.object, rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired, monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object, qualityProfileIds: PropTypes.arrayOf(PropTypes.object),
minimumAvailability: PropTypes.object.isRequired, minimumAvailability: PropTypes.object.isRequired,
searchForMovie: PropTypes.object.isRequired, searchForMovie: PropTypes.object.isRequired,
folder: PropTypes.string.isRequired, folder: PropTypes.string.isRequired,
@@ -58,7 +58,7 @@ class AddNewMovieModalContentConnector extends Component {
tmdbId, tmdbId,
rootFolderPath, rootFolderPath,
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
searchForMovie, searchForMovie,
tags tags
@@ -68,7 +68,7 @@ class AddNewMovieModalContentConnector extends Component {
tmdbId, tmdbId,
rootFolderPath: rootFolderPath.value, rootFolderPath: rootFolderPath.value,
monitor: monitor.value, monitor: monitor.value,
qualityProfileId: qualityProfileId.value, qualityProfileIds: qualityProfileIds.value,
minimumAvailability: minimumAvailability.value, minimumAvailability: minimumAvailability.value,
searchForMovie: searchForMovie.value, searchForMovie: searchForMovie.value,
tags: tags.value tags: tags.value
@@ -93,7 +93,7 @@ AddNewMovieModalContentConnector.propTypes = {
tmdbId: PropTypes.number.isRequired, tmdbId: PropTypes.number.isRequired,
rootFolderPath: PropTypes.object, rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired, monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object, qualityProfileIds: PropTypes.arrayOf(PropTypes.object),
minimumAvailability: PropTypes.object.isRequired, minimumAvailability: PropTypes.object.isRequired,
searchForMovie: PropTypes.object.isRequired, searchForMovie: PropTypes.object.isRequired,
tags: PropTypes.object.isRequired, tags: PropTypes.object.isRequired,
@@ -9,13 +9,15 @@
.underlay { .underlay {
@add-mixin cover; @add-mixin cover;
background-color: $white; background-color: var(--addMovieBackgroundColor);
transition: background 500ms; transition: background 500ms;
&:hover { &:hover {
background-color: #eaf2ff; background-color: var(--pageBackground);
box-shadow: 0 0 12px var(--black);
color: inherit; color: inherit;
text-decoration: none; text-decoration: none;
transition: all 200ms ease-in;
} }
} }
@@ -31,7 +33,7 @@
display: block; display: block;
margin-right: 20px; margin-right: 20px;
height: 250px; height: 250px;
background-color: $defaultColor; background-color: var(--defaultColor);
} }
.content { .content {
@@ -56,7 +58,7 @@
.year { .year {
margin-left: 10px; margin-left: 10px;
color: $disabledColor; color: var(--disabledColor);
} }
.icons { .icons {
@@ -75,7 +77,7 @@
.exclusionIcon { .exclusionIcon {
margin-left: 10px; margin-left: 10px;
color: $dangerColor; color: var(--dangerColor);
pointer-events: all; pointer-events: all;
} }
@@ -72,15 +72,19 @@ class AddNewMovieSearchResult extends Component {
colorImpairedMode, colorImpairedMode,
id, id,
monitored, monitored,
hasFile,
isAvailable, isAvailable,
queueStatus, queueStatus,
queueState, queueState,
runtime, runtime,
movieRuntimeFormat, movieRuntimeFormat,
certification certification,
statistics
} = this.props; } = this.props;
const {
movieFileCount
} = statistics;
const { const {
isNewAddMovieModalOpen isNewAddMovieModalOpen
} = this.state; } = this.state;
@@ -120,7 +124,7 @@ class AddNewMovieSearchResult extends Component {
isExistingMovie && isExistingMovie &&
<MovieIndexProgressBar <MovieIndexProgressBar
monitored={monitored} monitored={monitored}
hasFile={hasFile} hasFile={movieFileCount > 0}
status={status} status={status}
posterWidth={posterWidth} posterWidth={posterWidth}
detailedProgressBar={true} detailedProgressBar={true}
@@ -233,7 +237,7 @@ class AddNewMovieSearchResult extends Component {
{ {
isExistingMovie && isSmallScreen && isExistingMovie && isSmallScreen &&
<MovieStatusLabel <MovieStatusLabel
hasMovieFiles={hasFile} hasMovieFiles={movieFileCount > 0}
monitored={monitored} monitored={monitored}
isAvailable={isAvailable} isAvailable={isAvailable}
id={id} id={id}
@@ -290,7 +294,14 @@ AddNewMovieSearchResult.propTypes = {
queueState: PropTypes.string, queueState: PropTypes.string,
runtime: PropTypes.number.isRequired, runtime: PropTypes.number.isRequired,
movieRuntimeFormat: PropTypes.string.isRequired, movieRuntimeFormat: PropTypes.string.isRequired,
certification: PropTypes.string certification: PropTypes.string,
statistics: PropTypes.object
};
AddNewMovieSearchResult.defaultProps = {
statistics: {
movieFileCount: 0
}
}; };
export default AddNewMovieSearchResult; export default AddNewMovieSearchResult;
@@ -25,13 +25,13 @@ class ImportMovieFooter extends Component {
const { const {
defaultMonitor, defaultMonitor,
defaultQualityProfileId, defaultQualityProfileIds,
defaultMinimumAvailability defaultMinimumAvailability
} = props; } = props;
this.state = { this.state = {
monitor: defaultMonitor, monitor: defaultMonitor,
qualityProfileId: defaultQualityProfileId, qualityProfileIds: defaultQualityProfileIds,
minimumAvailability: defaultMinimumAvailability minimumAvailability: defaultMinimumAvailability
}; };
} }
@@ -39,16 +39,16 @@ class ImportMovieFooter extends Component {
componentDidUpdate(prevProps, prevState) { componentDidUpdate(prevProps, prevState) {
const { const {
defaultMonitor, defaultMonitor,
defaultQualityProfileId, defaultQualityProfileIds,
defaultMinimumAvailability, defaultMinimumAvailability,
isMonitorMixed, isMonitorMixed,
isQualityProfileIdMixed, isQualityProfileIdsMixed,
isMinimumAvailabilityMixed isMinimumAvailabilityMixed
} = this.props; } = this.props;
const { const {
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability minimumAvailability
} = this.state; } = this.state;
@@ -60,10 +60,10 @@ class ImportMovieFooter extends Component {
newState.monitor = defaultMonitor; newState.monitor = defaultMonitor;
} }
if (isQualityProfileIdMixed && qualityProfileId !== MIXED) { if (isQualityProfileIdsMixed && qualityProfileIds !== MIXED) {
newState.qualityProfileId = MIXED; newState.qualityProfileIds = MIXED;
} else if (!isQualityProfileIdMixed && qualityProfileId !== defaultQualityProfileId) { } else if (!isQualityProfileIdsMixed && qualityProfileIds !== defaultQualityProfileIds) {
newState.qualityProfileId = defaultQualityProfileId; newState.qualityProfileIds = defaultQualityProfileIds;
} }
if (isMinimumAvailabilityMixed && minimumAvailability !== MIXED) { if (isMinimumAvailabilityMixed && minimumAvailability !== MIXED) {
@@ -94,7 +94,7 @@ class ImportMovieFooter extends Component {
isImporting, isImporting,
isLookingUpMovie, isLookingUpMovie,
isMonitorMixed, isMonitorMixed,
isQualityProfileIdMixed, isQualityProfileIdsMixed,
isMinimumAvailabilityMixed, isMinimumAvailabilityMixed,
hasUnsearchedItems, hasUnsearchedItems,
importError, importError,
@@ -105,7 +105,7 @@ class ImportMovieFooter extends Component {
const { const {
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability minimumAvailability
} = this.state; } = this.state;
@@ -148,10 +148,10 @@ class ImportMovieFooter extends Component {
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileIds"
value={qualityProfileId} value={qualityProfileIds}
isDisabled={!selectedCount} isDisabled={!selectedCount}
includeMixed={isQualityProfileIdMixed} includeMixed={isQualityProfileIdsMixed}
onChange={this.onInputChange} onChange={this.onInputChange}
/> />
</div> </div>
@@ -251,10 +251,10 @@ ImportMovieFooter.propTypes = {
isImporting: PropTypes.bool.isRequired, isImporting: PropTypes.bool.isRequired,
isLookingUpMovie: PropTypes.bool.isRequired, isLookingUpMovie: PropTypes.bool.isRequired,
defaultMonitor: PropTypes.string.isRequired, defaultMonitor: PropTypes.string.isRequired,
defaultQualityProfileId: PropTypes.number, defaultQualityProfileIds: PropTypes.arrayOf(PropTypes.number),
defaultMinimumAvailability: PropTypes.string, defaultMinimumAvailability: PropTypes.string,
isMonitorMixed: PropTypes.bool.isRequired, isMonitorMixed: PropTypes.bool.isRequired,
isQualityProfileIdMixed: PropTypes.bool.isRequired, isQualityProfileIdsMixed: PropTypes.bool.isRequired,
isMinimumAvailabilityMixed: PropTypes.bool.isRequired, isMinimumAvailabilityMixed: PropTypes.bool.isRequired,
hasUnsearchedItems: PropTypes.bool.isRequired, hasUnsearchedItems: PropTypes.bool.isRequired,
importError: PropTypes.object, importError: PropTypes.object,
@@ -18,7 +18,7 @@ function createMapStateToProps() {
(addMovie, importMovie, selectedIds) => { (addMovie, importMovie, selectedIds) => {
const { const {
monitor: defaultMonitor, monitor: defaultMonitor,
qualityProfileId: defaultQualityProfileId, qualityProfileIds: defaultQualityProfileIds,
minimumAvailability: defaultMinimumAvailability minimumAvailability: defaultMinimumAvailability
} = addMovie.defaults; } = addMovie.defaults;
@@ -30,7 +30,7 @@ function createMapStateToProps() {
} = importMovie; } = importMovie;
const isMonitorMixed = isMixed(items, selectedIds, defaultMonitor, 'monitor'); const isMonitorMixed = isMixed(items, selectedIds, defaultMonitor, 'monitor');
const isQualityProfileIdMixed = isMixed(items, selectedIds, defaultQualityProfileId, 'qualityProfileId'); const isQualityProfileIdsMixed = isMixed(items, selectedIds, defaultQualityProfileIds, 'qualityProfileIds');
const isMinimumAvailabilityMixed = isMixed(items, selectedIds, defaultMinimumAvailability, 'minimumAvailability'); const isMinimumAvailabilityMixed = isMixed(items, selectedIds, defaultMinimumAvailability, 'minimumAvailability');
const hasUnsearchedItems = !isLookingUpMovie && items.some((item) => !item.isPopulated); const hasUnsearchedItems = !isLookingUpMovie && items.some((item) => !item.isPopulated);
@@ -39,10 +39,10 @@ function createMapStateToProps() {
isLookingUpMovie, isLookingUpMovie,
isImporting, isImporting,
defaultMonitor, defaultMonitor,
defaultQualityProfileId, defaultQualityProfileIds,
defaultMinimumAvailability, defaultMinimumAvailability,
isMonitorMixed, isMonitorMixed,
isQualityProfileIdMixed, isQualityProfileIdsMixed,
isMinimumAvailabilityMixed, isMinimumAvailabilityMixed,
importError, importError,
hasUnsearchedItems hasUnsearchedItems
@@ -11,7 +11,7 @@ function ImportMovieRow(props) {
const { const {
id, id,
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
selectedMovie, selectedMovie,
isExistingMovie, isExistingMovie,
@@ -62,8 +62,8 @@ function ImportMovieRow(props) {
<VirtualTableRowCell className={styles.qualityProfile}> <VirtualTableRowCell className={styles.qualityProfile}>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileIds"
value={qualityProfileId} value={qualityProfileIds}
onChange={onInputChange} onChange={onInputChange}
/> />
</VirtualTableRowCell> </VirtualTableRowCell>
@@ -74,7 +74,7 @@ function ImportMovieRow(props) {
ImportMovieRow.propTypes = { ImportMovieRow.propTypes = {
id: PropTypes.string.isRequired, id: PropTypes.string.isRequired,
monitor: PropTypes.string.isRequired, monitor: PropTypes.string.isRequired,
qualityProfileId: PropTypes.number.isRequired, qualityProfileIds: PropTypes.arrayOf(PropTypes.number).isRequired,
minimumAvailability: PropTypes.string.isRequired, minimumAvailability: PropTypes.string.isRequired,
selectedMovie: PropTypes.object, selectedMovie: PropTypes.object,
isExistingMovie: PropTypes.bool.isRequired, isExistingMovie: PropTypes.bool.isRequired,
@@ -15,7 +15,7 @@ class ImportMovieTable extends Component {
const { const {
unmappedFolders, unmappedFolders,
defaultMonitor, defaultMonitor,
defaultQualityProfileId, defaultQualityProfileIds,
defaultMinimumAvailability, defaultMinimumAvailability,
onMovieLookup, onMovieLookup,
onSetImportMovieValue onSetImportMovieValue
@@ -23,7 +23,7 @@ class ImportMovieTable extends Component {
const values = { const values = {
monitor: defaultMonitor, monitor: defaultMonitor,
qualityProfileId: defaultQualityProfileId, qualityProfileIds: defaultQualityProfileIds,
minimumAvailability: defaultMinimumAvailability minimumAvailability: defaultMinimumAvailability
}; };
@@ -167,7 +167,7 @@ ImportMovieTable.propTypes = {
items: PropTypes.arrayOf(PropTypes.object), items: PropTypes.arrayOf(PropTypes.object),
unmappedFolders: PropTypes.arrayOf(PropTypes.object), unmappedFolders: PropTypes.arrayOf(PropTypes.object),
defaultMonitor: PropTypes.string.isRequired, defaultMonitor: PropTypes.string.isRequired,
defaultQualityProfileId: PropTypes.number, defaultQualityProfileIds: PropTypes.arrayOf(PropTypes.number),
defaultMinimumAvailability: PropTypes.string, defaultMinimumAvailability: PropTypes.string,
allSelected: PropTypes.bool.isRequired, allSelected: PropTypes.bool.isRequired,
allUnselected: PropTypes.bool.isRequired, allUnselected: PropTypes.bool.isRequired,
@@ -13,7 +13,7 @@ function createMapStateToProps() {
(addMovie, importMovie, dimensions, allMovies) => { (addMovie, importMovie, dimensions, allMovies) => {
return { return {
defaultMonitor: addMovie.defaults.monitor, defaultMonitor: addMovie.defaults.monitor,
defaultQualityProfileId: addMovie.defaults.qualityProfileId, defaultQualityProfileIds: addMovie.defaults.qualityProfileIds,
defaultMinimumAvailability: addMovie.defaults.minimumAvailability, defaultMinimumAvailability: addMovie.defaults.minimumAvailability,
items: importMovie.items, items: importMovie.items,
isSmallScreen: dimensions.isSmallScreen, isSmallScreen: dimensions.isSmallScreen,
@@ -4,7 +4,7 @@
width: 100%; width: 100%;
&:hover { &:hover {
background-color: $menuItemHoverBackgroundColor; background-color: var(--menuItemHoverBackgroundColor);
} }
} }
@@ -17,7 +17,7 @@
composes: link from '~Components/Link/Link.css'; composes: link from '~Components/Link/Link.css';
margin-left: auto; margin-left: auto;
color: $textColor; color: var(--textColor);
} }
.tmdbLinkIcon { .tmdbLinkIcon {
@@ -7,10 +7,10 @@
padding: 6px 16px; padding: 6px 16px;
width: 100%; width: 100%;
height: 35px; height: 35px;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor);
} }
.loading { .loading {
@@ -38,9 +38,9 @@
.content { .content {
padding: 4px; padding: 4px;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
} }
.searchContainer { .searchContainer {
@@ -49,12 +49,12 @@
.searchIconContainer { .searchIconContainer {
width: 58px; width: 58px;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-right: none; border-right: none;
border-radius: 4px; border-radius: 4px;
border-top-right-radius: 0; border-top-right-radius: 0;
border-bottom-right-radius: 0; border-bottom-right-radius: 0;
background-color: #edf1f2; background-color: var(--searchIconContainerBackgroundColor);
text-align: center; text-align: center;
line-height: 33px; line-height: 33px;
} }
@@ -5,6 +5,7 @@ import FormInputButton from 'Components/Form/FormInputButton';
import TextInput from 'Components/Form/TextInput'; import TextInput from 'Components/Form/TextInput';
import Icon from 'Components/Icon'; import Icon from 'Components/Icon';
import Link from 'Components/Link/Link'; import Link from 'Components/Link/Link';
import SpinnerButton from 'Components/Link/SpinnerButton';
import LoadingIndicator from 'Components/Loading/LoadingIndicator'; import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import Portal from 'Components/Portal'; import Portal from 'Components/Portal';
import { icons, kinds } from 'Helpers/Props'; import { icons, kinds } from 'Helpers/Props';
@@ -242,7 +243,7 @@ class ImportMovieSelectMovie extends Component {
<FormInputButton <FormInputButton
kind={kinds.DEFAULT} kind={kinds.DEFAULT}
spinnerIcon={icons.REFRESH} spinnerIcon={icons.REFRESH}
canSpin={true} ButtonComponent={SpinnerButton}
isSpinning={isFetching} isSpinning={isFetching}
onPress={this.onRefreshPress} onPress={this.onRefreshPress}
> >
@@ -9,7 +9,7 @@
.year { .year {
margin-left: 5px; margin-left: 5px;
color: $disabledColor; color: var(--disabledColor);
} }
.existing { .existing {
+6 -3
View File
@@ -4,6 +4,7 @@ import React from 'react';
import DocumentTitle from 'react-document-title'; import DocumentTitle from 'react-document-title';
import { Provider } from 'react-redux'; import { Provider } from 'react-redux';
import PageConnector from 'Components/Page/PageConnector'; import PageConnector from 'Components/Page/PageConnector';
import ApplyTheme from './ApplyTheme';
import AppRoutes from './AppRoutes'; import AppRoutes from './AppRoutes';
function App({ store, history }) { function App({ store, history }) {
@@ -11,9 +12,11 @@ function App({ store, history }) {
<DocumentTitle title={window.Radarr.instanceName}> <DocumentTitle title={window.Radarr.instanceName}>
<Provider store={store}> <Provider store={store}>
<ConnectedRouter history={history}> <ConnectedRouter history={history}>
<PageConnector> <ApplyTheme>
<AppRoutes app={App} /> <PageConnector>
</PageConnector> <AppRoutes app={App} />
</PageConnector>
</ApplyTheme>
</ConnectedRouter> </ConnectedRouter>
</Provider> </Provider>
</DocumentTitle> </DocumentTitle>
+2 -2
View File
@@ -22,7 +22,7 @@ import MediaManagementConnector from 'Settings/MediaManagement/MediaManagementCo
import MetadataSettings from 'Settings/Metadata/MetadataSettings'; import MetadataSettings from 'Settings/Metadata/MetadataSettings';
import NotificationSettings from 'Settings/Notifications/NotificationSettings'; import NotificationSettings from 'Settings/Notifications/NotificationSettings';
import Profiles from 'Settings/Profiles/Profiles'; import Profiles from 'Settings/Profiles/Profiles';
import Quality from 'Settings/Quality/Quality'; import QualityConnector from 'Settings/Quality/QualityConnector';
import Settings from 'Settings/Settings'; import Settings from 'Settings/Settings';
import TagSettings from 'Settings/Tags/TagSettings'; import TagSettings from 'Settings/Tags/TagSettings';
import UISettingsConnector from 'Settings/UI/UISettingsConnector'; import UISettingsConnector from 'Settings/UI/UISettingsConnector';
@@ -143,7 +143,7 @@ function AppRoutes(props) {
<Route <Route
path="/settings/quality" path="/settings/quality"
component={Quality} component={QualityConnector}
/> />
<Route <Route
+49
View File
@@ -0,0 +1,49 @@
import PropTypes from 'prop-types';
import React, { Fragment, useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import themes from 'Styles/Themes';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.ui.item.theme || window.Radarr.theme,
(
theme
) => {
return {
theme
};
}
);
}
function ApplyTheme({ theme, children }) {
// Update the CSS Variables
const updateCSSVariables = useCallback(() => {
const arrayOfVariableKeys = Object.keys(themes[theme]);
const arrayOfVariableValues = Object.values(themes[theme]);
// Loop through each array key and set the CSS Variables
arrayOfVariableKeys.forEach((cssVariableKey, index) => {
// Based on our snippet from MDN
document.documentElement.style.setProperty(
`--${cssVariableKey}`,
arrayOfVariableValues[index]
);
});
}, [theme]);
// On Component Mount and Component Update
useEffect(() => {
updateCSSVariables(theme);
}, [updateCSSVariables, theme]);
return <Fragment>{children}</Fragment>;
}
ApplyTheme.propTypes = {
theme: PropTypes.string.isRequired,
children: PropTypes.object.isRequired
};
export default connect(createMapStateToProps)(ApplyTheme);
+2 -2
View File
@@ -2,11 +2,11 @@
display: flex; display: flex;
overflow-x: hidden; overflow-x: hidden;
padding: 5px; padding: 5px;
border-bottom: 1px solid $borderColor; border-bottom: 1px solid var(--borderColor);
font-size: $defaultFontSize; font-size: $defaultFontSize;
&:hover { &:hover {
background-color: $tableRowHoverBackgroundColor; background-color: var(--tableRowHoverBackgroundColor);
} }
} }
@@ -24,7 +24,7 @@ function createMissingMovieIdsSelector() {
const inCinemas = movie.inCinemas; const inCinemas = movie.inCinemas;
if ( if (
!movie.hasFile && (!movie.statistics || movie.statistics.movieFileCount === 0) &&
moment(inCinemas).isAfter(start) && moment(inCinemas).isAfter(start) &&
moment(inCinemas).isBefore(end) && moment(inCinemas).isBefore(end) &&
isBefore(movie.inCinemas) && isBefore(movie.inCinemas) &&
+5 -5
View File
@@ -2,8 +2,8 @@
flex: 1 0 14.28%; flex: 1 0 14.28%;
overflow: hidden; overflow: hidden;
min-height: 70px; min-height: 70px;
border-bottom: 1px solid $calendarBorderColor; border-bottom: 1px solid var(--calendarBorderColor);
border-left: 1px solid $calendarBorderColor; border-left: 1px solid var(--calendarBorderColor);
} }
.isSingleDay { .isSingleDay {
@@ -12,14 +12,14 @@
.dayOfMonth { .dayOfMonth {
padding-right: 5px; padding-right: 5px;
border-bottom: 1px solid $calendarBorderColor; border-bottom: 1px solid var(--calendarBorderColor);
text-align: right; text-align: right;
} }
.isToday { .isToday {
background-color: $calendarTodayBackgroundColor; background-color: var(--calendarTodayBackgroundColor);
} }
.isDifferentMonth { .isDifferentMonth {
color: $disabledColor; color: var(--disabledColor);
} }
+1 -1
View File
@@ -1,6 +1,6 @@
.days { .days {
display: flex; display: flex;
border-right: 1px solid $calendarBorderColor; border-right: 1px solid var(--calendarBorderColor);
} }
.day, .day,
+2 -2
View File
@@ -1,6 +1,6 @@
.dayOfWeek { .dayOfWeek {
flex: 1 0 14.28%; flex: 1 0 14.28%;
background-color: #e4eaec; background-color: var(--calendarBackgroudColor);
text-align: center; text-align: center;
} }
@@ -9,5 +9,5 @@
} }
.isToday { .isToday {
background-color: $calendarTodayBackgroundColor; background-color: var(--calendarTodayBackgroundColor);
} }
+66 -16
View File
@@ -1,9 +1,11 @@
$fullColorGradient: rgba(244, 245, 246, 0.2);
.event { .event {
overflow-x: hidden; overflow-x: hidden;
margin: 4px 2px; margin: 4px 2px;
padding: 5px; padding: 5px;
border-bottom: 1px solid $borderColor; border-bottom: 1px solid var(--calendarBorderColor);
border-left: 4px solid $borderColor; border-left: 4px solid var(--calendarBorderColor);
font-size: 12px; font-size: 12px;
&:global(.colorImpaired) { &:global(.colorImpaired) {
@@ -15,10 +17,10 @@
composes: link from '~Components/Link/Link.css'; composes: link from '~Components/Link/Link.css';
display: block; display: block;
color: $defaultColor; color: var(--defaultColor);
&:hover { &:hover {
color: $defaultColor; color: var(--defaultColor);
text-decoration: none; text-decoration: none;
} }
} }
@@ -29,7 +31,7 @@
} }
.movieInfo { .movieInfo {
color: $calendarTextDim; color: var(--calendarTextDim);
} }
.movieTitle, .movieTitle,
@@ -40,7 +42,7 @@
} }
.movieTitle { .movieTitle {
color: #3a3f51; color: var(--calendarTextDimAlternate);
font-size: $defaultFontSize; font-size: $defaultFontSize;
} }
@@ -53,37 +55,85 @@
*/ */
.downloaded { .downloaded {
border-left-color: $successColor !important; border-left-color: var(--successColor) !important;
&:global(.fullColor) {
background-color: rgba(39, 194, 76, 0.4) !important;
}
&:global(.colorImpaired) { &:global(.colorImpaired) {
border-left-color: color($successColor, saturation(+15%)) !important; border-left-color: color(var(--successColor), saturation(+15%)) !important;
} }
} }
.queue { .queue {
border-left-color: $purple !important; border-left-color: var(--purple) !important;
&:global(.fullColor) {
background-color: rgba(122, 67, 182, 0.4) !important;
}
} }
.unmonitored { .unmonitored {
border-left-color: $gray !important; border-left-color: var(--gray) !important;
&:global(.fullColor) {
background-color: rgba(173, 173, 173, 0.5) !important;
}
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
}
&:global(.fullColor.colorImpaired) {
background: repeating-linear-gradient(45deg, $fullColorGradient, $fullColorGradient 5px, transparent 5px, transparent 10px);
}
} }
.missingUnmonitored { .missingUnmonitored {
border-left-color: $warningColor !important; border-left-color: var(--warningColor) !important;
&:global(.fullColor) {
background-color: rgba(255, 165, 0, 0.6) !important;
}
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px); background: repeating-linear-gradient(45deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
}
&:global(.fullColor.colorImpaired) {
background: repeating-linear-gradient(45deg, $fullColorGradient, $fullColorGradient 5px, transparent 5px, transparent 10px);
} }
} }
.missingMonitored { .missingMonitored {
border-left-color: $dangerColor !important; border-left-color: var(--dangerColor) !important;
&:global(.fullColor) {
background-color: rgba(240, 80, 80, 0.6) !important;
}
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px); background: repeating-linear-gradient(90deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
}
&:global(.fullColor.colorImpaired) {
background: repeating-linear-gradient(90deg, $fullColorGradient, $fullColorGradient 5px, transparent 5px, transparent 10px);
} }
} }
.continuing { .unaired {
border-left-color: $primaryColor !important; border-left-color: var(--primaryColor) !important;
&:global(.fullColor) {
background-color: rgba(93, 156, 236, 0.4) !important;
}
&:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
}
&:global(.fullColor.colorImpaired) {
background: repeating-linear-gradient(90deg, $fullColorGradient, $fullColorGradient 5px, transparent 5px, transparent 10px);
}
} }
@@ -32,6 +32,7 @@ class CalendarEvent extends Component {
queueItem, queueItem,
showMovieInformation, showMovieInformation,
showCutoffUnmetIcon, showCutoffUnmetIcon,
fullColorEvents,
colorImpairedMode, colorImpairedMode,
date date
} = this.props; } = this.props;
@@ -62,7 +63,8 @@ class CalendarEvent extends Component {
styles.event, styles.event,
styles.link, styles.link,
styles[statusStyle], styles[statusStyle],
colorImpairedMode && 'colorImpaired' colorImpairedMode && 'colorImpaired',
fullColorEvents && 'fullColor'
)} )}
// component="div" // component="div"
to={link} to={link}
@@ -97,7 +99,7 @@ class CalendarEvent extends Component {
<Icon <Icon
className={styles.statusIcon} className={styles.statusIcon}
name={icons.MOVIE_FILE} name={icons.MOVIE_FILE}
kind={kinds.WARNING} kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
title={translate('QualityCutoffHasNotBeenMet')} title={translate('QualityCutoffHasNotBeenMet')}
/> />
} }
@@ -142,11 +144,12 @@ CalendarEvent.propTypes = {
digitalRelease: PropTypes.string, digitalRelease: PropTypes.string,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
certification: PropTypes.string, certification: PropTypes.string,
hasFile: PropTypes.bool.isRequired, hasFile: PropTypes.bool,
grabbed: PropTypes.bool, grabbed: PropTypes.bool,
queueItem: PropTypes.object, queueItem: PropTypes.object,
showMovieInformation: PropTypes.bool.isRequired, showMovieInformation: PropTypes.bool.isRequired,
showCutoffUnmetIcon: PropTypes.bool.isRequired, showCutoffUnmetIcon: PropTypes.bool.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
timeFormat: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired,
colorImpairedMode: PropTypes.bool.isRequired, colorImpairedMode: PropTypes.bool.isRequired,
date: PropTypes.string.isRequired date: PropTypes.string.isRequired
@@ -2,7 +2,6 @@ import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import QueueDetails from 'Activity/Queue/QueueDetails'; import QueueDetails from 'Activity/Queue/QueueDetails';
import CircularProgressBar from 'Components/CircularProgressBar'; import CircularProgressBar from 'Components/CircularProgressBar';
import colors from 'Styles/Variables/colors';
import translate from 'Utilities/String/translate'; import translate from 'Utilities/String/translate';
function CalendarEventQueueDetails(props) { function CalendarEventQueueDetails(props) {
@@ -35,7 +34,7 @@ function CalendarEventQueueDetails(props) {
progress={progress} progress={progress}
size={20} size={20}
strokeWidth={2} strokeWidth={2}
strokeColor={colors.purple} strokeColor={'#7a43b6'}
/> />
</div> </div>
} }
+10 -1
View File
@@ -9,6 +9,7 @@ import styles from './Legend.css';
function Legend(props) { function Legend(props) {
const { const {
showCutoffUnmetIcon, showCutoffUnmetIcon,
fullColorEvents,
colorImpairedMode colorImpairedMode
} = props; } = props;
@@ -19,7 +20,7 @@ function Legend(props) {
<LegendIconItem <LegendIconItem
name={translate('CutoffUnmet')} name={translate('CutoffUnmet')}
icon={icons.MOVIE_FILE} icon={icons.MOVIE_FILE}
kind={kinds.WARNING} kind={fullColorEvents ? kinds.DEFAULT : kinds.WARNING}
tooltip={translate('QualityOrLangCutoffHasNotBeenMet')} tooltip={translate('QualityOrLangCutoffHasNotBeenMet')}
/> />
); );
@@ -31,12 +32,14 @@ function Legend(props) {
<LegendItem <LegendItem
style='ended' style='ended'
name={translate('DownloadedAndMonitored')} name={translate('DownloadedAndMonitored')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
<LegendItem <LegendItem
style='availNotMonitored' style='availNotMonitored'
name={translate('DownloadedButNotMonitored')} name={translate('DownloadedButNotMonitored')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
</div> </div>
@@ -45,12 +48,14 @@ function Legend(props) {
<LegendItem <LegendItem
style='missingMonitored' style='missingMonitored'
name={translate('MissingMonitoredAndConsideredAvailable')} name={translate('MissingMonitoredAndConsideredAvailable')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
<LegendItem <LegendItem
style='missingUnmonitored' style='missingUnmonitored'
name={translate('MissingNotMonitored')} name={translate('MissingNotMonitored')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
</div> </div>
@@ -59,12 +64,14 @@ function Legend(props) {
<LegendItem <LegendItem
style='queue' style='queue'
name={translate('Queued')} name={translate('Queued')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
<LegendItem <LegendItem
style='continuing' style='continuing'
name={translate('Unreleased')} name={translate('Unreleased')}
fullColorEvents={fullColorEvents}
colorImpairedMode={colorImpairedMode} colorImpairedMode={colorImpairedMode}
/> />
</div> </div>
@@ -79,7 +86,9 @@ function Legend(props) {
} }
Legend.propTypes = { Legend.propTypes = {
view: PropTypes.string.isRequired,
showCutoffUnmetIcon: PropTypes.bool.isRequired, showCutoffUnmetIcon: PropTypes.bool.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
colorImpairedMode: PropTypes.bool.isRequired colorImpairedMode: PropTypes.bool.isRequired
}; };
@@ -6,10 +6,12 @@ import Legend from './Legend';
function createMapStateToProps() { function createMapStateToProps() {
return createSelector( return createSelector(
(state) => state.calendar.options, (state) => state.calendar.options,
(state) => state.calendar.view,
createUISettingsSelector(), createUISettingsSelector(),
(calendarOptions, uiSettings) => { (calendarOptions, view, uiSettings) => {
return { return {
...calendarOptions, ...calendarOptions,
view,
colorImpairedMode: uiSettings.enableColorImpairedMode colorImpairedMode: uiSettings.enableColorImpairedMode
}; };
} }
@@ -8,6 +8,7 @@ function LegendIconItem(props) {
name, name,
icon, icon,
kind, kind,
darken,
tooltip tooltip
} = props; } = props;
@@ -19,6 +20,7 @@ function LegendIconItem(props) {
<Icon <Icon
className={styles.icon} className={styles.icon}
name={icon} name={icon}
darken={darken}
kind={kind} kind={kind}
/> />
@@ -31,7 +33,12 @@ LegendIconItem.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
icon: PropTypes.object.isRequired, icon: PropTypes.object.isRequired,
kind: PropTypes.string.isRequired, kind: PropTypes.string.isRequired,
darken: PropTypes.bool.isRequired,
tooltip: PropTypes.string.isRequired tooltip: PropTypes.string.isRequired
}; };
LegendIconItem.defaultProps = {
darken: false
};
export default LegendIconItem; export default LegendIconItem;
+14 -10
View File
@@ -1,3 +1,5 @@
$fullColorGradient: rgba(244, 245, 246, 0.2);
.legendItemContainer { .legendItemContainer {
margin-right: 5px; margin-right: 5px;
width: 220px; width: 220px;
@@ -20,53 +22,55 @@
.queue { .queue {
composes: legendItemColor; composes: legendItemColor;
background-color: $queueColor; background-color: var(--queueColor);
} }
.continuing { .continuing {
composes: legendItemColor; composes: legendItemColor;
background-color: $primaryColor; background-color: var(--primaryColor);
} }
.availNotMonitored { .availNotMonitored {
composes: legendItemColor; composes: legendItemColor;
background-color: $darkGray; background-color: var(--darkGray);
} }
.ended { .ended {
composes: legendItemColor; composes: legendItemColor;
background-color: $successColor; background-color: var(--successColor);
} }
.missingMonitored { .missingMonitored {
composes: legendItemColor; composes: legendItemColor;
background-color: $dangerColor; background-color: var(--dangerColor);
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px); background: repeating-linear-gradient(90deg, color(var(--dangerColor) shade(5%)), color(var(--dangerColor) shade(5%)) 5px, color(var(--dangerColor) shade(15%)) 5px, color(var(--dangerColor) shade(15%)) 10px);
} }
} }
.missingUnmonitored { .missingUnmonitored {
composes: legendItemColor; composes: legendItemColor;
background-color: $warningColor; background-color: var(--warningColor);
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px); background: repeating-linear-gradient(45deg, var(--warningColor), var(--warningColor) 5px, color(var(--warningColor) tint(15%)) 5px, color(var(--warningColor) tint(15%)) 10px);
} }
} }
.missingMonitoredColorImpaired { .missingMonitoredColorImpaired {
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px); background: repeating-linear-gradient(90deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
color: var(--white);
} }
.missingUnmonitoredColorImpaired { .missingUnmonitoredColorImpaired {
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px); background: repeating-linear-gradient(45deg, var(--colorImpairedGradientDark), var(--colorImpairedGradientDark) 5px, var(--colorImpairedGradient) 5px, var(--colorImpairedGradient) 10px);
color: var(--white);
} }
.legendItemText { .legendItemText {
+4 -1
View File
@@ -7,6 +7,7 @@ function LegendItem(props) {
const { const {
name, name,
style, style,
fullColorEvents,
colorImpairedMode colorImpairedMode
} = props; } = props;
@@ -16,7 +17,8 @@ function LegendItem(props) {
className={classNames( className={classNames(
styles.legendItem, styles.legendItem,
styles[style], styles[style],
colorImpairedMode && 'colorImpaired' colorImpairedMode && 'colorImpaired',
fullColorEvents && 'fullColor'
)} )}
/> />
<div className={classNames(styles.legendItemText, colorImpairedMode && styles[`${style}ColorImpaired`])}> <div className={classNames(styles.legendItemText, colorImpairedMode && styles[`${style}ColorImpaired`])}>
@@ -29,6 +31,7 @@ function LegendItem(props) {
LegendItem.propTypes = { LegendItem.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
style: PropTypes.string.isRequired, style: PropTypes.string.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
colorImpairedMode: PropTypes.bool.isRequired colorImpairedMode: PropTypes.bool.isRequired
}; };
@@ -26,14 +26,16 @@ class CalendarOptionsModalContent extends Component {
firstDayOfWeek, firstDayOfWeek,
calendarWeekColumnHeader, calendarWeekColumnHeader,
timeFormat, timeFormat,
enableColorImpairedMode enableColorImpairedMode,
fullColorEvents
} = props; } = props;
this.state = { this.state = {
firstDayOfWeek, firstDayOfWeek,
calendarWeekColumnHeader, calendarWeekColumnHeader,
timeFormat, timeFormat,
enableColorImpairedMode enableColorImpairedMode,
fullColorEvents
}; };
} }
@@ -94,6 +96,7 @@ class CalendarOptionsModalContent extends Component {
const { const {
showMovieInformation, showMovieInformation,
showCutoffUnmetIcon, showCutoffUnmetIcon,
fullColorEvents,
onModalClose onModalClose
} = this.props; } = this.props;
@@ -136,6 +139,18 @@ class CalendarOptionsModalContent extends Component {
onChange={this.onOptionInputChange} onChange={this.onOptionInputChange}
/> />
</FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('FullColorEvents')}</FormLabel>
<FormInputGroup
type={inputTypes.CHECK}
name="fullColorEvents"
value={fullColorEvents}
helpText={translate('FullColorEventsHelpText')}
onChange={this.onOptionInputChange}
/>
</FormGroup>
</Form> </Form>
</FieldSet> </FieldSet>
@@ -176,7 +191,9 @@ class CalendarOptionsModalContent extends Component {
value={timeFormat} value={timeFormat}
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
/> />
</FormGroup><FormGroup> </FormGroup>
<FormGroup>
<FormLabel>{translate('EnableColorImpairedMode')}</FormLabel> <FormLabel>{translate('EnableColorImpairedMode')}</FormLabel>
<FormInputGroup <FormInputGroup
@@ -187,7 +204,6 @@ class CalendarOptionsModalContent extends Component {
onChange={this.onGlobalInputChange} onChange={this.onGlobalInputChange}
/> />
</FormGroup> </FormGroup>
</Form> </Form>
</FieldSet> </FieldSet>
</ModalBody> </ModalBody>
@@ -209,6 +225,7 @@ CalendarOptionsModalContent.propTypes = {
calendarWeekColumnHeader: PropTypes.string.isRequired, calendarWeekColumnHeader: PropTypes.string.isRequired,
timeFormat: PropTypes.string.isRequired, timeFormat: PropTypes.string.isRequired,
enableColorImpairedMode: PropTypes.bool.isRequired, enableColorImpairedMode: PropTypes.bool.isRequired,
fullColorEvents: PropTypes.bool.isRequired,
dispatchSetCalendarOption: PropTypes.func.isRequired, dispatchSetCalendarOption: PropTypes.func.isRequired,
dispatchSaveUISettings: PropTypes.func.isRequired, dispatchSaveUISettings: PropTypes.func.isRequired,
onModalClose: PropTypes.func.isRequired onModalClose: PropTypes.func.isRequired
@@ -22,7 +22,7 @@ function getUrls(state) {
tags tags
} = state; } = state;
let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/v3/calendar/Radarr.ics?`; let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/v4/calendar/Radarr.ics?`;
if (unmonitored) { if (unmonitored) {
icalUrl += 'unmonitored=true&'; icalUrl += 'unmonitored=true&';
@@ -4,7 +4,7 @@
.year { .year {
margin-left: 5px; margin-left: 5px;
color: $disabledColor; color: var(--disabledColor);
} }
.poster { .poster {
@@ -46,7 +46,7 @@ class AddNewCollectionMovieModalContent extends Component {
onInputChange, onInputChange,
rootFolderPath, rootFolderPath,
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
searchForMovie searchForMovie
} = this.props; } = this.props;
@@ -126,13 +126,13 @@ class AddNewCollectionMovieModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>{translate('QualityProfile')}</FormLabel> <FormLabel>{translate('QualityProfiles')}</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileIds"
onChange={this.onQualityProfileIdChange} onChange={this.onQualityProfileIdChange}
{...qualityProfileId} {...qualityProfileIds}
/> />
</FormGroup> </FormGroup>
@@ -189,7 +189,7 @@ AddNewCollectionMovieModalContent.propTypes = {
addError: PropTypes.object, addError: PropTypes.object,
rootFolderPath: PropTypes.object, rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired, monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object, qualityProfileIds: PropTypes.object,
minimumAvailability: PropTypes.object.isRequired, minimumAvailability: PropTypes.object.isRequired,
searchForMovie: PropTypes.object.isRequired, searchForMovie: PropTypes.object.isRequired,
folder: PropTypes.string.isRequired, folder: PropTypes.string.isRequired,
@@ -25,7 +25,7 @@ function createMapStateToProps() {
const collectionDefaults = { const collectionDefaults = {
rootFolderPath: collection.rootFolderPath, rootFolderPath: collection.rootFolderPath,
monitor: 'movieOnly', monitor: 'movieOnly',
qualityProfileId: collection.qualityProfileId, qualityProfileIds: collection.qualityProfileIds,
minimumAvailability: collection.minimumAvailability, minimumAvailability: collection.minimumAvailability,
searchForMovie: collection.searchOnAdd, searchForMovie: collection.searchOnAdd,
tags: [] tags: []
@@ -70,7 +70,7 @@ class AddNewCollectionMovieModalContentConnector extends Component {
title, title,
rootFolderPath, rootFolderPath,
monitor, monitor,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
searchForMovie, searchForMovie,
tags tags
@@ -81,7 +81,7 @@ class AddNewCollectionMovieModalContentConnector extends Component {
title, title,
rootFolderPath: rootFolderPath.value, rootFolderPath: rootFolderPath.value,
monitor: monitor.value, monitor: monitor.value,
qualityProfileId: qualityProfileId.value, qualityProfileIds: qualityProfileIds.value,
minimumAvailability: minimumAvailability.value, minimumAvailability: minimumAvailability.value,
searchForMovie: searchForMovie.value, searchForMovie: searchForMovie.value,
tags: tags.value tags: tags.value
@@ -109,7 +109,7 @@ AddNewCollectionMovieModalContentConnector.propTypes = {
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
rootFolderPath: PropTypes.object, rootFolderPath: PropTypes.object,
monitor: PropTypes.object.isRequired, monitor: PropTypes.object.isRequired,
qualityProfileId: PropTypes.object, qualityProfileIds: PropTypes.object,
minimumAvailability: PropTypes.object.isRequired, minimumAvailability: PropTypes.object.isRequired,
searchForMovie: PropTypes.object.isRequired, searchForMovie: PropTypes.object.isRequired,
tags: PropTypes.object.isRequired, tags: PropTypes.object.isRequired,
@@ -46,7 +46,7 @@ class EditCollectionModalContent extends Component {
const { const {
monitored, monitored,
qualityProfileId, qualityProfileIds,
minimumAvailability, minimumAvailability,
// Id, // Id,
rootFolderPath, rootFolderPath,
@@ -104,12 +104,12 @@ class EditCollectionModalContent extends Component {
</FormGroup> </FormGroup>
<FormGroup> <FormGroup>
<FormLabel>{translate('QualityProfile')}</FormLabel> <FormLabel>{translate('QualityProfiles')}</FormLabel>
<FormInputGroup <FormInputGroup
type={inputTypes.QUALITY_PROFILE_SELECT} type={inputTypes.QUALITY_PROFILE_SELECT}
name="qualityProfileId" name="qualityProfileIds"
{...qualityProfileId} {...qualityProfileIds}
onChange={onInputChange} onChange={onInputChange}
/> />
</FormGroup> </FormGroup>
@@ -39,7 +39,7 @@ function createMapStateToProps() {
const movieSettings = { const movieSettings = {
monitored: collection.monitored, monitored: collection.monitored,
qualityProfileId: collection.qualityProfileId, qualityProfileIds: collection.qualityProfileIds,
minimumAvailability: collection.minimumAvailability, minimumAvailability: collection.minimumAvailability,
rootFolderPath: collection.rootFolderPath, rootFolderPath: collection.rootFolderPath,
searchOnAdd: collection.searchOnAdd searchOnAdd: collection.searchOnAdd
@@ -6,7 +6,7 @@ $hoverScale: 1.05;
&:hover { &:hover {
z-index: 2; z-index: 2;
box-shadow: 0 0 10px $black; box-shadow: 0 0 10px var(--black);
transition: all 200ms ease-in; transition: all 200ms ease-in;
.poster { .poster {
@@ -28,7 +28,7 @@ $hoverScale: 1.05;
.poster { .poster {
position: relative; position: relative;
display: block; display: block;
background-color: $defaultColor; background-color: var(--defaultColor);
} }
.overlay { .overlay {
@@ -44,7 +44,7 @@ $hoverScale: 1.05;
.overlayTitle { .overlayTitle {
padding: 5px; padding: 5px;
color: $offWhite; color: var(--offWhite);
text-align: left; text-align: left;
font-weight: bold; font-weight: bold;
font-size: 15px; font-size: 15px;
@@ -67,7 +67,7 @@ $hoverScale: 1.05;
z-index: 3; z-index: 3;
border-radius: 4px; border-radius: 4px;
background-color: #707070; background-color: #707070;
color: $white; color: var(--white);
font-size: $smallFontSize; font-size: $smallFontSize;
opacity: 0; opacity: 0;
transition: opacity 0; transition: opacity 0;
@@ -77,7 +77,7 @@ $hoverScale: 1.05;
composes: button from '~Components/Link/IconButton.css'; composes: button from '~Components/Link/IconButton.css';
&:hover { &:hover {
color: $radarrYellow; color: var(--radarrYellow);
} }
} }
@@ -102,16 +102,16 @@ $hoverScale: 1.05;
position: relative; position: relative;
display: block; display: block;
background-color: $defaultColor; background-color: var(--defaultColor);
} }
.monitorToggleButton { .monitorToggleButton {
composes: toggleButton from '~Components/MonitorToggleButton.css'; composes: toggleButton from '~Components/MonitorToggleButton.css';
width: 25px; width: 25px;
color: $white; color: var(--white);
&:hover { &:hover {
color: $iconButtonHoverLightColor; color: var(--iconButtonHoverLightColor);
} }
} }
@@ -3,7 +3,7 @@
align-items: stretch; align-items: stretch;
overflow: hidden; overflow: hidden;
margin: 2px 4px; margin: 2px 4px;
border: 1px solid $borderColor; border: 1px solid var(--borderColor);
border-radius: 4px; border-radius: 4px;
background-color: #eee; background-color: #eee;
cursor: default; cursor: default;
@@ -17,34 +17,34 @@
padding: 0 4px; padding: 0 4px;
border-left: 4px; border-left: 4px;
border-left-style: solid; border-left-style: solid;
background-color: $white; background-color: var(--white);
color: $defaultColor; color: var(--defaultColor);
} }
.primary { .primary {
border-color: $primaryColor; border-color: var(--primaryColor);
} }
.danger { .danger {
border-color: $dangerColor; border-color: var(--dangerColor);
} }
.success { .success {
border-color: $successColor; border-color: var(--successColor);
} }
.purple { .purple {
border-color: $purple; border-color: var(--purple);
} }
.warning { .warning {
border-color: $warningColor; border-color: var(--warningColor);
} }
.info { .info {
border-color: $infoColor; border-color: var(--infoColor);
} }
.queue { .queue {
border-color: $queueColor; border-color: var(--queueColor);
} }
@@ -17,11 +17,13 @@ class CollectionMovieLabel extends Component {
status, status,
monitored, monitored,
isAvailable, isAvailable,
hasFile,
onMonitorTogglePress, onMonitorTogglePress,
isSaving isSaving,
statistics
} = this.props; } = this.props;
const { movieFileCount } = statistics;
return ( return (
<div className={styles.movie}> <div className={styles.movie}>
<div className={styles.movieTitle}> <div className={styles.movieTitle}>
@@ -46,11 +48,11 @@ class CollectionMovieLabel extends Component {
<div <div
className={classNames( className={classNames(
styles.movieStatus, styles.movieStatus,
styles[getStatusStyle(status, monitored, hasFile, isAvailable, 'kinds')] styles[getStatusStyle(status, monitored, movieFileCount > 0, isAvailable, 'kinds')]
)} )}
> >
{ {
hasFile ? translate('Downloaded') : translate('Missing') movieFileCount > 0 ? translate('Downloaded') : translate('Missing')
} }
</div> </div>
} }
@@ -63,9 +65,9 @@ CollectionMovieLabel.propTypes = {
id: PropTypes.number, id: PropTypes.number,
title: PropTypes.string.isRequired, title: PropTypes.string.isRequired,
status: PropTypes.string, status: PropTypes.string,
statistics: PropTypes.object.isRequired,
isAvailable: PropTypes.bool, isAvailable: PropTypes.bool,
monitored: PropTypes.bool, monitored: PropTypes.bool,
hasFile: PropTypes.bool,
isSaving: PropTypes.bool.isRequired, isSaving: PropTypes.bool.isRequired,
movieFile: PropTypes.object, movieFile: PropTypes.object,
movieFileId: PropTypes.number, movieFileId: PropTypes.number,
@@ -75,9 +77,7 @@ CollectionMovieLabel.propTypes = {
CollectionMovieLabel.defaultProps = { CollectionMovieLabel.defaultProps = {
isSaving: false, isSaving: false,
statistics: { statistics: {
episodeFileCount: 0, movieFileCount: 0
totalEpisodeCount: 0,
percentOfEpisodes: 0
} }
}; };
@@ -104,7 +104,7 @@ $hoverScale: 1.05;
width: 25px; width: 25px;
&:hover { &:hover {
color: $iconButtonHoverLightColor; color: var(--iconButtonHoverLightColor);
} }
} }
@@ -131,7 +131,7 @@ $hoverScale: 1.05;
width: 20px; width: 20px;
&:hover { &:hover {
color: $iconButtonHoverLightColor; color: var(--iconButtonHoverLightColor);
} }
} }
} }
@@ -96,7 +96,7 @@ class CollectionOverview extends Component {
render() { render() {
const { const {
monitored, monitored,
qualityProfileId, qualityProfileIds,
rootFolderPath, rootFolderPath,
genres, genres,
id, id,
@@ -212,7 +212,7 @@ class CollectionOverview extends Component {
<span className={styles.qualityProfileName}> <span className={styles.qualityProfileName}>
{ {
<QualityProfileNameConnector <QualityProfileNameConnector
qualityProfileId={qualityProfileId} qualityProfileIds={qualityProfileIds}
/> />
} }
</span> </span>
@@ -325,7 +325,7 @@ class CollectionOverview extends Component {
CollectionOverview.propTypes = { CollectionOverview.propTypes = {
id: PropTypes.number.isRequired, id: PropTypes.number.isRequired,
monitored: PropTypes.bool.isRequired, monitored: PropTypes.bool.isRequired,
qualityProfileId: PropTypes.number.isRequired, qualityProfileIds: PropTypes.number.isRequired,
minimumAvailability: PropTypes.string.isRequired, minimumAvailability: PropTypes.string.isRequired,
searchOnAdd: PropTypes.bool.isRequired, searchOnAdd: PropTypes.bool.isRequired,
rootFolderPath: PropTypes.string.isRequired, rootFolderPath: PropTypes.string.isRequired,
@@ -5,7 +5,7 @@
.container { .container {
&:hover { &:hover {
.content { .content {
background-color: $tableRowHoverBackgroundColor; background-color: var(--tableRowHoverBackgroundColor);
} }
} }
} }
+1
View File
@@ -15,6 +15,7 @@ export const REFRESH_MOVIE = 'RefreshMovie';
export const RENAME_FILES = 'RenameFiles'; export const RENAME_FILES = 'RenameFiles';
export const RENAME_MOVIE = 'RenameMovie'; export const RENAME_MOVIE = 'RenameMovie';
export const RESET_API_KEY = 'ResetApiKey'; export const RESET_API_KEY = 'ResetApiKey';
export const RESET_QUALITY_DEFINITIONS = 'ResetQualityDefinitions';
export const RSS_SYNC = 'RssSync'; export const RSS_SYNC = 'RssSync';
export const MOVIE_SEARCH = 'MoviesSearch'; export const MOVIE_SEARCH = 'MoviesSearch';
export const IMPORT_LIST_SYNC = 'ImportListSync'; export const IMPORT_LIST_SYNC = 'ImportListSync';
+12 -12
View File
@@ -7,25 +7,25 @@
} }
.danger { .danger {
border-color: $alertDangerBorderColor; border-color: var(--alertDangerBorderColor);
background-color: $alertDangerBackgroundColor; background-color: var(--alertDangerBackgroundColor);
color: $alertDangerColor; color: var(--alertDangerColor);
} }
.info { .info {
border-color: $alertInfoBorderColor; border-color: var(--alertInfoBorderColor);
background-color: $alertInfoBackgroundColor; background-color: var(--alertInfoBackgroundColor);
color: $alertInfoColor; color: var(--alertInfoColor);
} }
.success { .success {
border-color: $alertSuccessBorderColor; border-color: var(--alertSuccessBorderColor);
background-color: $alertSuccessBackgroundColor; background-color: var(--alertSuccessBackgroundColor);
color: $alertSuccessColor; color: var(--alertSuccessColor);
} }
.warning { .warning {
border-color: $alertWarningBorderColor; border-color: var(--alertWarningBorderColor);
background-color: $alertWarningBackgroundColor; background-color: var(--alertWarningBackgroundColor);
color: $alertWarningColor; color: var(--alertWarningColor);
} }
+3 -3
View File
@@ -3,9 +3,9 @@
margin: 10px; margin: 10px;
padding: 10px; padding: 10px;
border-radius: 3px; border-radius: 3px;
background-color: $white; background-color: var(--cardBackgroundColor);
box-shadow: 0 0 10px 1px $cardShadowColor; box-shadow: 0 0 10px 1px var(--cardShadowColor);
color: $defaultColor; color: var(--defaultColor);
} }
.underlay { .underlay {
@@ -1,6 +1,5 @@
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React, { Component } from 'react'; import React, { Component } from 'react';
import colors from 'Styles/Variables/colors';
import styles from './CircularProgressBar.css'; import styles from './CircularProgressBar.css';
class CircularProgressBar extends Component { class CircularProgressBar extends Component {
@@ -132,7 +131,7 @@ CircularProgressBar.defaultProps = {
containerClassName: styles.circularProgressBarContainer, containerClassName: styles.circularProgressBarContainer,
size: 60, size: 60,
strokeWidth: 5, strokeWidth: 5,
strokeColor: colors.radarrYellow, strokeColor: '#ffc230',
showProgressText: false showProgressText: false
}; };
+1 -1
View File
@@ -13,7 +13,7 @@
width: 100%; width: 100%;
border: 0; border: 0;
border-bottom: 1px solid #e5e5e5; border-bottom: 1px solid #e5e5e5;
color: #3a3f51; color: var(--textColor);
font-size: 21px; font-size: 21px;
line-height: inherit; line-height: inherit;
@@ -13,7 +13,7 @@
} }
.faqLink { .faqLink {
color: $alertWarningColor; color: var(--alertWarningColor);
font-weight: bold; font-weight: bold;
} }
@@ -3,7 +3,7 @@
margin-bottom: 5px; margin-bottom: 5px;
&:hover { &:hover {
background-color: $tableRowHoverBackgroundColor; background-color: var(--tableRowHoverBackgroundColor);
} }
} }
@@ -17,5 +17,5 @@
.or { .or {
margin: 0 3px; margin: 0 3px;
color: $themeDarkColor; color: var(--themeDarkColor);
} }
@@ -4,7 +4,7 @@
padding: 5px; padding: 5px;
&:hover { &:hover {
background-color: $tableRowHoverBackgroundColor; background-color: var(--tableRowHoverBackgroundColor);
} }
} }
@@ -27,10 +27,10 @@
overflow-y: auto; overflow-y: auto;
max-height: 200px; max-height: 200px;
width: 100%; width: 100%;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor);
} }
} }
@@ -46,5 +46,5 @@
} }
.suggestionHighlighted { .suggestionHighlighted {
background-color: $menuItemHoverBackgroundColor; background-color: var(--menuItemHoverBackgroundColor);
} }
+16 -16
View File
@@ -32,21 +32,21 @@
height: 20px; height: 20px;
border: 1px solid #ccc; border: 1px solid #ccc;
border-radius: 2px; border-radius: 2px;
background-color: $white; background-color: var(--white);
color: $white; color: var(--white);
text-align: center; text-align: center;
line-height: 20px; line-height: 20px;
} }
.checkbox:focus + .input { .checkbox:focus + .input {
outline: 0; outline: 0;
border-color: $inputFocusBorderColor; border-color: var(--inputFocusBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor);
} }
.dangerIsChecked { .dangerIsChecked {
border-color: $dangerColor; border-color: var(--dangerColor);
background-color: $dangerColor; background-color: var(--dangerColor);
&.isDisabled { &.isDisabled {
opacity: 0.7; opacity: 0.7;
@@ -54,8 +54,8 @@
} }
.primaryIsChecked { .primaryIsChecked {
border-color: $primaryColor; border-color: var(--primaryColor);
background-color: $primaryColor; background-color: var(--primaryColor);
&.isDisabled { &.isDisabled {
opacity: 0.7; opacity: 0.7;
@@ -63,8 +63,8 @@
} }
.successIsChecked { .successIsChecked {
border-color: $successColor; border-color: var(--successColor);
background-color: $successColor; background-color: var(--successColor);
&.isDisabled { &.isDisabled {
opacity: 0.7; opacity: 0.7;
@@ -72,8 +72,8 @@
} }
.warningIsChecked { .warningIsChecked {
border-color: $warningColor; border-color: var(--warningColor);
background-color: $warningColor; background-color: var(--warningColor);
&.isDisabled { &.isDisabled {
opacity: 0.7; opacity: 0.7;
@@ -82,15 +82,15 @@
.isNotChecked { .isNotChecked {
&.isDisabled { &.isDisabled {
border-color: $disabledCheckInputColor; border-color: var(--disabledCheckInputColor);
background-color: $disabledCheckInputColor; background-color: var(--disabledCheckInputColor);
opacity: 0.7; opacity: 0.7;
} }
} }
.isIndeterminate { .isIndeterminate {
border-color: $gray; border-color: var(--gray);
background-color: $gray; background-color: var(--gray);
} }
.helpText { .helpText {
@@ -39,7 +39,7 @@
.dropdownArrowContainerDisabled { .dropdownArrowContainerDisabled {
composes: dropdownArrowContainer; composes: dropdownArrowContainer;
color: $disabledInputColor; color: var(--disabledInputColor);
} }
.optionsContainer { .optionsContainer {
@@ -50,9 +50,9 @@
.options { .options {
composes: scroller from '~Components/Scroller/Scroller.css'; composes: scroller from '~Components/Scroller/Scroller.css';
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
} }
.optionsModal { .optionsModal {
@@ -76,9 +76,9 @@
.optionsModalScroller { .optionsModalScroller {
composes: scroller from '~Components/Scroller/Scroller.css'; composes: scroller from '~Components/Scroller/Scroller.css';
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
} }
.loading { .loading {
@@ -90,7 +90,7 @@
display: flex; display: flex;
justify-content: flex-end; justify-content: flex-end;
height: 40px; height: 40px;
border-bottom: 1px solid $borderColor; border-bottom: 1px solid var(--borderColor);
} }
.mobileCloseButton { .mobileCloseButton {
@@ -100,6 +100,6 @@
line-height: 40px; line-height: 40px;
&:hover { &:hover {
color: $modalCloseButtonHoverColor; color: var(--modalCloseButtonHoverColor);
} }
} }
@@ -7,7 +7,7 @@
cursor: default; cursor: default;
&:hover { &:hover {
background-color: #f8f8f8; background-color: var(--inputHoverBackgroundColor);
} }
} }
@@ -24,17 +24,17 @@
} }
.isSelected { .isSelected {
background-color: #e2e2e2; background-color: var(--inputSelectedBackgroundColor);
&:hover { &:hover {
background-color: #e2e2e2; background-color: var(--inputSelectedBackgroundColor);
} }
&.isMobile { &.isMobile {
background-color: inherit; background-color: inherit;
.iconContainer { .iconContainer {
color: $primaryColor; color: var(--primaryColor);
} }
} }
} }
@@ -49,7 +49,7 @@
.isMobile { .isMobile {
height: 50px; height: 50px;
border-bottom: 1px solid $borderColor; border-bottom: 1px solid var(--borderColor);
&:last-child { &:last-child {
border: none; border: none;
@@ -3,5 +3,5 @@
} }
.isDisabled { .isDisabled {
color: $disabledInputColor; color: var(--disabledInputColor);
} }
@@ -2,33 +2,19 @@ import classNames from 'classnames';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import Button from 'Components/Link/Button'; import Button from 'Components/Link/Button';
import SpinnerButton from 'Components/Link/SpinnerButton';
import { kinds } from 'Helpers/Props'; import { kinds } from 'Helpers/Props';
import styles from './FormInputButton.css'; import styles from './FormInputButton.css';
function FormInputButton(props) { function FormInputButton(props) {
const { const {
className, className,
canSpin, ButtonComponent,
isLastButton, isLastButton,
...otherProps ...otherProps
} = props; } = props;
if (canSpin) {
return (
<SpinnerButton
className={classNames(
className,
!isLastButton && styles.middleButton
)}
kind={kinds.PRIMARY}
{...otherProps}
/>
);
}
return ( return (
<Button <ButtonComponent
className={classNames( className={classNames(
className, className,
!isLastButton && styles.middleButton !isLastButton && styles.middleButton
@@ -41,14 +27,14 @@ function FormInputButton(props) {
FormInputButton.propTypes = { FormInputButton.propTypes = {
className: PropTypes.string.isRequired, className: PropTypes.string.isRequired,
isLastButton: PropTypes.bool.isRequired, ButtonComponent: PropTypes.elementType.isRequired,
canSpin: PropTypes.bool.isRequired isLastButton: PropTypes.bool.isRequired
}; };
FormInputButton.defaultProps = { FormInputButton.defaultProps = {
className: styles.button, className: styles.button,
isLastButton: true, ButtonComponent: Button,
canSpin: false isLastButton: true
}; };
export default FormInputButton; export default FormInputButton;
@@ -6,7 +6,6 @@
.inputGroup { .inputGroup {
display: flex; display: flex;
flex: 1 1 auto; flex: 1 1 auto;
flex-wrap: wrap;
} }
.inputContainer { .inputContainer {
@@ -40,7 +39,7 @@
} }
.pendingChangesIcon { .pendingChangesIcon {
color: $warningColor; color: var(--warningColor);
font-size: 20px; font-size: 20px;
line-height: 35px; line-height: 35px;
} }
@@ -20,6 +20,7 @@ import NumberInput from './NumberInput';
import OAuthInputConnector from './OAuthInputConnector'; import OAuthInputConnector from './OAuthInputConnector';
import PasswordInput from './PasswordInput'; import PasswordInput from './PasswordInput';
import PathInputConnector from './PathInputConnector'; import PathInputConnector from './PathInputConnector';
import PlexMachineInputConnector from './PlexMachineInputConnector';
import QualityProfileSelectInputConnector from './QualityProfileSelectInputConnector'; import QualityProfileSelectInputConnector from './QualityProfileSelectInputConnector';
import RootFolderSelectInputConnector from './RootFolderSelectInputConnector'; import RootFolderSelectInputConnector from './RootFolderSelectInputConnector';
import TagInputConnector from './TagInputConnector'; import TagInputConnector from './TagInputConnector';
@@ -62,6 +63,9 @@ function getComponent(type) {
case inputTypes.PATH: case inputTypes.PATH:
return PathInputConnector; return PathInputConnector;
case inputTypes.PLEX_MACHINE_SELECT:
return PlexMachineInputConnector;
case inputTypes.QUALITY_PROFILE_SELECT: case inputTypes.QUALITY_PROFILE_SELECT:
return QualityProfileSelectInputConnector; return QualityProfileSelectInputConnector;
@@ -1,14 +1,14 @@
.helpText { .helpText {
margin-top: 5px; margin-top: 5px;
color: $helpTextColor; color: var(--helpTextColor);
line-height: 20px; line-height: 20px;
} }
.isError { .isError {
color: $dangerColor; color: var(--dangerColor);
.link { .link {
color: $dangerColor; color: var(--dangerColor);
&:hover { &:hover {
color: #e01313; color: #e01313;
@@ -17,10 +17,10 @@
} }
.isWarning { .isWarning {
color: $warningColor; color: var(--warningColor);
.link { .link {
color: $warningColor; color: var(--warningColor);
&:hover { &:hover {
color: #e36c00; color: #e36c00;
+2 -2
View File
@@ -7,11 +7,11 @@
} }
.hasError { .hasError {
color: $dangerColor; color: var(--dangerColor);
} }
.isAdvanced { .isAdvanced {
color: $advancedFormLabelColor; color: var(--advancedFormLabelColor);
} }
@media only screen and (max-width: $breakpointLarge) { @media only screen and (max-width: $breakpointLarge) {
@@ -18,11 +18,11 @@
@add-mixin truncate; @add-mixin truncate;
margin-left: 15px; margin-left: 15px;
color: $darkGray; color: var(--darkGray);
font-size: $smallFontSize; font-size: $smallFontSize;
} }
.divider { .divider {
border: none; border: none;
border-bottom: 1px solid $lightGray; border-bottom: 1px solid var(--lightGray);
} }
@@ -18,7 +18,7 @@
flex: 1 10 0; flex: 1 10 0;
margin-left: 15px; margin-left: 15px;
color: $gray; color: var(--gray);
text-align: right; text-align: right;
font-size: $smallFontSize; font-size: $smallFontSize;
} }
+10 -9
View File
@@ -2,26 +2,27 @@
padding: 6px 16px; padding: 6px 16px;
width: 100%; width: 100%;
height: 35px; height: 35px;
border: 1px solid $inputBorderColor; border: 1px solid var(--inputBorderColor);
border-radius: 4px; border-radius: 4px;
background-color: $white; background-color: var(--inputBackgroundColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor);
color: var(--textColor);
&:focus { &:focus {
outline: 0; outline: 0;
border-color: $inputFocusBorderColor; border-color: var(--inputFocusBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor);
} }
} }
.hasError { .hasError {
border-color: $inputErrorBorderColor; border-color: var(--inputErrorBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputErrorBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputErrorBoxShadowColor);
} }
.hasWarning { .hasWarning {
border-color: $inputWarningBorderColor; border-color: var(--inputWarningBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputWarningBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputWarningBoxShadowColor);
} }
.hasButton { .hasButton {
@@ -7,8 +7,8 @@
&.isFocused { &.isFocused {
outline: 0; outline: 0;
border-color: $inputFocusBorderColor; border-color: var(--inputFocusBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor);
} }
} }
@@ -1,7 +1,7 @@
.itemContainer { .itemContainer {
display: flex; display: flex;
margin-bottom: 3px; margin-bottom: 3px;
border-bottom: 1px solid $inputBorderColor; border-bottom: 1px solid var(--inputBorderColor);
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
+12 -11
View File
@@ -5,6 +5,7 @@ import { kinds } from 'Helpers/Props';
function OAuthInput(props) { function OAuthInput(props) {
const { const {
className,
label, label,
authorizing, authorizing,
error, error,
@@ -12,21 +13,21 @@ function OAuthInput(props) {
} = props; } = props;
return ( return (
<div> <SpinnerErrorButton
<SpinnerErrorButton className={className}
kind={kinds.PRIMARY} kind={kinds.PRIMARY}
isSpinning={authorizing} isSpinning={authorizing}
error={error} error={error}
onPress={onPress} onPress={onPress}
> >
{label} {label}
</SpinnerErrorButton> </SpinnerErrorButton>
</div>
); );
} }
OAuthInput.propTypes = { OAuthInput.propTypes = {
label: PropTypes.string.isRequired, className: PropTypes.string,
label: PropTypes.oneOfType([PropTypes.string, PropTypes.object]).isRequired,
authorizing: PropTypes.bool.isRequired, authorizing: PropTypes.bool.isRequired,
error: PropTypes.object, error: PropTypes.object,
onPress: PropTypes.func.isRequired onPress: PropTypes.func.isRequired
@@ -0,0 +1,44 @@
import PropTypes from 'prop-types';
import React from 'react';
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
import SelectInput from './SelectInput';
function PlexMachineInput(props) {
const {
isFetching,
isDisabled,
value,
values,
onChange,
...otherProps
} = props;
const helpText = 'Authenticate with plex.tv to show servers to use for authentication';
return (
<>
{
isFetching ?
<LoadingIndicator /> :
<SelectInput
value={value}
values={values}
isDisabled={isDisabled}
onChange={onChange}
helpText={helpText}
{...otherProps}
/>
}
</>
);
}
PlexMachineInput.propTypes = {
isFetching: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
value: PropTypes.string,
values: PropTypes.arrayOf(PropTypes.object).isRequired,
onChange: PropTypes.func.isRequired
};
export default PlexMachineInput;
@@ -0,0 +1,115 @@
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import { fetchPlexResources } from 'Store/Actions/settingsActions';
import PlexMachineInput from './PlexMachineInput';
function createMapStateToProps() {
return createSelector(
(state, { value }) => value,
(state) => state.oAuth,
(state) => state.settings.plex,
(value, oAuth, plex) => {
let values = [{ key: value, value }];
let isDisabled = true;
if (plex.isPopulated) {
const serverValues = plex.items.filter((item) => item.provides.includes('server')).map((item) => {
return ({
key: item.clientIdentifier,
value: `${item.name} / ${item.owned ? 'Owner' : 'User'} / ${item.clientIdentifier}`
});
});
if (serverValues.find((item) => item.key === value)) {
values = serverValues;
} else {
values = values.concat(serverValues);
}
isDisabled = false;
}
return ({
accessToken: oAuth.result?.accessToken,
values,
isDisabled,
...plex
});
}
);
}
const mapDispatchToProps = {
dispatchFetchPlexResources: fetchPlexResources
};
class PlexMachineInputConnector extends Component {
//
// Lifecycle
componentDidMount = () => {
const {
accessToken,
dispatchFetchPlexResources
} = this.props;
if (accessToken) {
dispatchFetchPlexResources({ accessToken });
}
};
componentDidUpdate(prevProps) {
const {
accessToken,
dispatchFetchPlexResources
} = this.props;
const oldToken = prevProps.accessToken;
if (accessToken && accessToken !== oldToken) {
dispatchFetchPlexResources({ accessToken });
}
}
render() {
const {
isFetching,
isPopulated,
isDisabled,
value,
values,
onChange
} = this.props;
return (
<PlexMachineInput
isFetching={isFetching}
isPopulated={isPopulated}
isDisabled={isDisabled}
value={value}
values={values}
onChange={onChange}
{...this.props}
/>
);
}
}
PlexMachineInputConnector.propTypes = {
dispatchFetchPlexResources: PropTypes.func.isRequired,
name: PropTypes.string.isRequired,
value: PropTypes.string.isRequired,
values: PropTypes.arrayOf(PropTypes.object).isRequired,
isFetching: PropTypes.bool.isRequired,
isPopulated: PropTypes.bool.isRequired,
isDisabled: PropTypes.bool.isRequired,
error: PropTypes.object,
oAuth: PropTypes.object,
accessToken: PropTypes.string,
onChange: PropTypes.func.isRequired
};
export default connect(createMapStateToProps, mapDispatchToProps)(PlexMachineInputConnector);
@@ -5,7 +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 SelectInput from './SelectInput'; import EnhancedSelectInput from './EnhancedSelectInput';
function createMapStateToProps() { function createMapStateToProps() {
return createSelector( return createSelector(
@@ -45,40 +45,14 @@ function createMapStateToProps() {
class QualityProfileSelectInputConnector extends Component { class QualityProfileSelectInputConnector extends Component {
//
// Lifecycle
componentDidMount() {
const {
name,
value,
values
} = this.props;
if (!value || !values.some((v) => v.key === value) ) {
const firstValue = _.find(values, (option) => !isNaN(parseInt(option.key)));
if (firstValue) {
this.onChange({ name, value: firstValue.key });
}
}
}
//
// Listeners
onChange = ({ name, value }) => {
this.props.onChange({ name, value: parseInt(value) });
};
// //
// Render // Render
render() { render() {
return ( return (
<SelectInput <EnhancedSelectInput
{...this.props} {...this.props}
onChange={this.onChange} onChange={this.props.onChange}
/> />
); );
} }
@@ -86,7 +60,7 @@ class QualityProfileSelectInputConnector extends Component {
QualityProfileSelectInputConnector.propTypes = { QualityProfileSelectInputConnector.propTypes = {
name: PropTypes.string.isRequired, name: PropTypes.string.isRequired,
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]), value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.arrayOf(PropTypes.string)]),
values: PropTypes.arrayOf(PropTypes.object).isRequired, values: PropTypes.arrayOf(PropTypes.object).isRequired,
includeNoChange: PropTypes.bool.isRequired, includeNoChange: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired onChange: PropTypes.func.isRequired
@@ -21,17 +21,17 @@
.movieFolder { .movieFolder {
@add-mixin truncate; @add-mixin truncate;
color: $disabledColor; color: var(--disabledColor);
} }
.freeSpace { .freeSpace {
margin-left: 15px; margin-left: 15px;
color: $darkGray; color: var(--darkGray);
font-size: $smallFontSize; font-size: $smallFontSize;
} }
.isMissing { .isMissing {
margin-left: 15px; margin-left: 15px;
color: $dangerColor; color: var(--dangerColor);
font-size: $smallFontSize; font-size: $smallFontSize;
} }
@@ -20,13 +20,13 @@
.movieFolder { .movieFolder {
@add-mixin truncate; @add-mixin truncate;
flex: 0 1 auto; flex: 0 1 auto;
color: $disabledColor; color: var(--disabledColor);
} }
.freeSpace { .freeSpace {
flex: 0 0 auto; flex: 0 0 auto;
margin-left: 15px; margin-left: 15px;
color: $gray; color: var(--gray);
text-align: right; text-align: right;
font-size: $smallFontSize; font-size: $smallFontSize;
} }
@@ -12,6 +12,10 @@
composes: hasWarning from '~Components/Form/Input.css'; composes: hasWarning from '~Components/Form/Input.css';
} }
.hasButton {
composes: hasButton from '~Components/Form/Input.css';
}
.isDisabled { .isDisabled {
opacity: 0.7; opacity: 0.7;
cursor: not-allowed; cursor: not-allowed;
@@ -28,6 +28,7 @@ class SelectInput extends Component {
isDisabled, isDisabled,
hasError, hasError,
hasWarning, hasWarning,
hasButton,
autoFocus, autoFocus,
onBlur onBlur
} = this.props; } = this.props;
@@ -38,6 +39,7 @@ class SelectInput extends Component {
className, className,
hasError && styles.hasError, hasError && styles.hasError,
hasWarning && styles.hasWarning, hasWarning && styles.hasWarning,
hasButton && styles.hasButton,
isDisabled && disabledClassName isDisabled && disabledClassName
)} )}
disabled={isDisabled} disabled={isDisabled}
@@ -80,6 +82,7 @@ SelectInput.propTypes = {
isDisabled: PropTypes.bool, isDisabled: PropTypes.bool,
hasError: PropTypes.bool, hasError: PropTypes.bool,
hasWarning: PropTypes.bool, hasWarning: PropTypes.bool,
hasButton: PropTypes.bool,
autoFocus: PropTypes.bool.isRequired, autoFocus: PropTypes.bool.isRequired,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onBlur: PropTypes.func onBlur: PropTypes.func
+4 -2
View File
@@ -7,8 +7,8 @@
&.isFocused { &.isFocused {
outline: 0; outline: 0;
border-color: $inputFocusBorderColor; border-color: var(--inputFocusBorderColor);
box-shadow: inset 0 1px 1px $inputBoxShadowColor, 0 0 8px $inputFocusBoxShadowColor; box-shadow: inset 0 1px 1px var(--inputBoxShadowColor), 0 0 8px var(--inputFocusBoxShadowColor);
} }
} }
@@ -20,4 +20,6 @@
width: 0%; width: 0%;
height: 31px; height: 31px;
border: none; border: none;
background-color: var(--inputBackground);
color: var(--textColor);
} }
+1 -1
View File
@@ -3,7 +3,7 @@
} }
.readOnly { .readOnly {
background-color: #eee; background-color: var(--inputReadOnlyBackgroundColor);
} }
.hasError { .hasError {
+1 -1
View File
@@ -49,5 +49,5 @@
} }
.readOnly { .readOnly {
background-color: #eee; background-color: var(--inputReadOnlyBackgroundColor);
} }
+15 -7
View File
@@ -1,5 +1,5 @@
.danger { .danger {
color: $dangerColor; color: var(--dangerColor);
} }
.default { .default {
@@ -7,25 +7,33 @@
} }
.disabled { .disabled {
color: $disabledColor; color: var(--disabledColor);
} }
.info { .info {
color: $infoColor; color: var(--infoColor);
&:global(.darken) {
color: color(var(--infoColor) shade(30%));
}
} }
.pink { .pink {
color: $pink; color: var(--pink);
&:global(.darken) {
color: color(var(--pink) shade(30%));
}
} }
.success { .success {
color: $successColor; color: var(--successColor);
} }
.warning { .warning {
color: $warningColor; color: var(--warningColor);
} }
.purple { .purple {
color: $purple; color: var(--purple);
} }
+5 -1
View File
@@ -18,6 +18,7 @@ class Icon extends PureComponent {
kind, kind,
size, size,
title, title,
darken,
isSpinning, isSpinning,
...otherProps ...otherProps
} = this.props; } = this.props;
@@ -26,7 +27,8 @@ class Icon extends PureComponent {
<FontAwesomeIcon <FontAwesomeIcon
className={classNames( className={classNames(
className, className,
styles[kind] styles[kind],
darken && 'darken'
)} )}
icon={name} icon={name}
spin={isSpinning} spin={isSpinning}
@@ -59,6 +61,7 @@ Icon.propTypes = {
kind: PropTypes.string.isRequired, kind: PropTypes.string.isRequired,
size: PropTypes.number.isRequired, size: PropTypes.number.isRequired,
title: PropTypes.string, title: PropTypes.string,
darken: PropTypes.bool.isRequired,
isSpinning: PropTypes.bool.isRequired, isSpinning: PropTypes.bool.isRequired,
fixedWidth: PropTypes.bool.isRequired fixedWidth: PropTypes.bool.isRequired
}; };
@@ -66,6 +69,7 @@ Icon.propTypes = {
Icon.defaultProps = { Icon.defaultProps = {
kind: kinds.DEFAULT, kind: kinds.DEFAULT,
size: 14, size: 14,
darken: false,
isSpinning: false, isSpinning: false,
fixedWidth: false fixedWidth: false
}; };
+3 -3
View File
@@ -1,7 +1,7 @@
.label { .label {
display: inline-block; display: inline-block;
margin: 2px; margin: 2px;
color: $white; color: var(--white);
/** text-align: center; **/ /** text-align: center; **/
white-space: nowrap; white-space: nowrap;
line-height: 1; line-height: 1;
@@ -10,7 +10,7 @@
.title { .title {
margin-bottom: 2px; margin-bottom: 2px;
color: $helpTextColor; color: var(--helpTextColor);
font-size: 10px; font-size: 10px;
} }
@@ -36,5 +36,5 @@
/** Outline **/ /** Outline **/
.outline { .outline {
background-color: $white; background-color: var(--white);
} }
+34 -33
View File
@@ -3,7 +3,7 @@
margin: 2px; margin: 2px;
border: 1px solid; border: 1px solid;
border-radius: 2px; border-radius: 2px;
color: $white; color: var(--white);
text-align: center; text-align: center;
white-space: nowrap; white-space: nowrap;
line-height: 1; line-height: 1;
@@ -13,94 +13,95 @@
/** Kinds **/ /** Kinds **/
.danger { .danger {
border-color: $dangerColor; border-color: var(--dangerColor);
background-color: $dangerColor; background-color: var(--dangerColor);
&.outline { &.outline {
color: $dangerColor; color: var(--dangerColor);
} }
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px); background: repeating-linear-gradient(90deg, color(var(--dangerColor) shade(5%)), color(var(--dangerColor) shade(5%)) 5px, color(var(--dangerColor) shade(15%)) 5px, color(var(--dangerColor) shade(15%)) 10px);
} }
} }
.default { .default {
border-color: $themeLightColor; border-color: var(--themeLightColor);
background-color: $themeLightColor; background-color: var(--themeLightColor);
&.outline { &.outline {
color: $themeLightColor; color: var(--themeLightColor);
} }
} }
.disabled { .disabled {
border-color: $disabledColor; border-color: var(--disabledColor);
background-color: $disabledColor; background-color: var(--disabledColor);
&.outline { &.outline {
color: $disabledColor; color: var(--offWhite);
} }
} }
.info { .info {
border-color: $infoColor; border-color: var(--infoColor);
background-color: $infoColor; background-color: var(--infoColor);
color: var(--infoTextColor);
&.outline { &.outline {
color: $infoColor; color: var(--infoColor);
} }
} }
.inverse { .inverse {
border-color: $lightGray; border-color: var(--inverseLabelColor);
background-color: $lightGray; background-color: var(--inverseLabelColor);
color: $defaultColor; color: var(--inverseLabelTextColor);
&.outline { &.outline {
background-color: $defaultColor !important; background-color: var(--inverseLabelTextColor) !important;
color: $lightGray; color: var(--inverseLabelColor);
} }
} }
.primary { .primary {
border-color: $primaryColor; border-color: var(--primaryColor);
background-color: $primaryColor; background-color: var(--primaryColor);
&.outline { &.outline {
color: $primaryColor; color: var(--primaryColor);
} }
} }
.success { .success {
border-color: $successColor; border-color: var(--successColor);
background-color: $successColor; background-color: var(--successColor);
color: #eee; color: #eee;
&.outline { &.outline {
color: $successColor; color: var(--successColor);
} }
} }
.warning { .warning {
border-color: $warningColor; border-color: var(--warningColor);
background-color: $warningColor; background-color: var(--warningColor);
&.outline { &.outline {
color: $warningColor; color: var(--warningColor);
} }
&:global(.colorImpaired) { &:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px); background: repeating-linear-gradient(45deg, var(--warningColor), var(--warningColor) 5px, color(var(--warningColor) tint(15%)) 5px, color(var(--warningColor) tint(15%)) 10px);
} }
} }
.queue { .queue {
border-color: $queueColor; border-color: var(--queueColor);
background-color: $queueColor; background-color: var(--queueColor);
&.outline { &.outline {
color: $queueColor; color: var(--queueColor);
} }
} }
@@ -125,5 +126,5 @@
/** Outline **/ /** Outline **/
.outline { .outline {
background-color: $white; background-color: var(--disabledLabelColor);
} }
+30 -30
View File
@@ -19,62 +19,62 @@
} }
.danger { .danger {
border-color: $dangerBorderColor; border-color: var(--dangerBorderColor);
background-color: $dangerBackgroundColor; background-color: var(--dangerBackgroundColor);
color: $white; color: var(--white);
&:hover { &:hover {
border-color: $dangerHoverBorderColor; border-color: var(--dangerHoverBorderColor);
background-color: $dangerHoverBackgroundColor; background-color: var(--dangerHoverBackgroundColor);
color: $white; color: var(--white);
} }
} }
.default { .default {
border-color: $defaultBorderColor; border-color: var(--defaultBorderColor);
background-color: $defaultBackgroundColor; background-color: var(--defaultBackgroundColor);
color: $defaultColor; color: var(--defaultColor);
&:hover { &:hover {
border-color: $defaultHoverBorderColor; border-color: var(--defaultHoverBorderColor);
background-color: $defaultHoverBackgroundColor; background-color: var(--defaultHoverBackgroundColor);
color: $defaultColor; color: var(--defaultColor);
} }
} }
.primary { .primary {
border-color: $primaryBorderColor; border-color: var(--primaryBorderColor);
background-color: $primaryBackgroundColor; background-color: var(--primaryBackgroundColor);
color: $white; color: var(--white);
&:hover { &:hover {
border-color: $primaryHoverBorderColor; border-color: var(--primaryHoverBorderColor);
background-color: $primaryHoverBackgroundColor; background-color: var(--primaryHoverBackgroundColor);
color: $white; color: var(--white);
} }
} }
.success { .success {
border-color: $successBorderColor; border-color: var(--successBorderColor);
background-color: $successBackgroundColor; background-color: var(--successBackgroundColor);
color: $white; color: var(--white);
&:hover { &:hover {
border-color: $successHoverBorderColor; border-color: var(--successHoverBorderColor);
background-color: $successHoverBackgroundColor; background-color: var(--successHoverBackgroundColor);
color: $white; color: var(--white);
} }
} }
.warning { .warning {
border-color: $warningBorderColor; border-color: var(--warningBorderColor);
background-color: $warningBackgroundColor; background-color: var(--warningBackgroundColor);
color: $white; color: var(--white);
&:hover { &:hover {
border-color: $warningHoverBorderColor; border-color: var(--warningHoverBorderColor);
background-color: $warningHoverBackgroundColor; background-color: var(--warningHoverBackgroundColor);
color: $white; color: var(--white);
} }
} }
+2 -2
View File
@@ -12,10 +12,10 @@
&:hover { &:hover {
border: none; border: none;
background-color: inherit; background-color: inherit;
color: $iconButtonHoverColor; color: var(--iconButtonHoverColor);
} }
&.isDisabled { &.isDisabled {
color: $iconButtonDisabledColor; color: var(--iconButtonDisabledColor);
} }
} }
+2 -2
View File
@@ -15,10 +15,10 @@
} }
.to { .to {
color: $linkColor; color: var(--linkColor);
&:hover { &:hover {
color: $linkHoverColor; color: var(--linkHoverColor);
text-decoration: underline; text-decoration: underline;
} }
} }
@@ -26,7 +26,7 @@
.ripple { .ripple {
position: absolute; position: absolute;
border: 2px solid #3a3f51; border: 2px solid var(--themeDarkColor);
border-radius: 100%; border-radius: 100%;
animation: rippleContainer 1.25s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8); animation: rippleContainer 1.25s 0s infinite cubic-bezier(0.21, 0.53, 0.56, 0.8);
animation-fill-mode: both; animation-fill-mode: both;
+2 -2
View File
@@ -10,12 +10,12 @@
} }
&:hover { &:hover {
color: $toobarButtonHoverColor; color: var(--toobarButtonHoverColor);
} }
} }
.isDisabled { .isDisabled {
color: $disabledColor; color: var(--disabledColor);
pointer-events: none; pointer-events: none;
} }
+1 -1
View File
@@ -2,7 +2,7 @@
z-index: $popperZIndex; z-index: $popperZIndex;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background-color: $toolbarMenuItemBackgroundColor; background-color: var(--toolbarMenuItemBackgroundColor);
line-height: 20px; line-height: 20px;
} }
+5 -5
View File
@@ -5,19 +5,19 @@
padding: 10px 20px; padding: 10px 20px;
min-width: 150px; min-width: 150px;
max-width: 250px; max-width: 250px;
background-color: $toolbarMenuItemBackgroundColor; background-color: var(--toolbarMenuItemBackgroundColor);
color: $menuItemColor; color: var(--menuItemColor);
line-height: 20px; line-height: 20px;
&:hover, &:hover,
&:focus { &:focus {
background-color: $toolbarMenuItemHoverBackgroundColor; background-color: var(--toolbarMenuItemHoverBackgroundColor);
color: $menuItemHoverColor; color: var(--menuItemHoverColor);
text-decoration: none; text-decoration: none;
} }
} }
.isDisabled { .isDisabled {
color: $disabledColor; color: var(--disabledColor);
pointer-events: none; pointer-events: none;
} }

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