mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-06 13:31:28 -05:00
Compare commits
140 Commits
v3.2.0.504
...
native-the
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
315c2e1b88 | ||
|
|
d33bed6a36 | ||
|
|
3acc6a3f9d | ||
|
|
8d0a26e284 | ||
|
|
f0f8a4ffaf | ||
|
|
e7ff13085e | ||
|
|
6a8f6dc5f7 | ||
|
|
13c03d9958 | ||
|
|
5ce1829709 | ||
|
|
86da4e87ea | ||
|
|
a219b4a1b8 | ||
|
|
84dd10f032 | ||
|
|
f844cbecaf | ||
|
|
279692f9b1 | ||
|
|
6fcbdc5ba3 | ||
|
|
750b0331ab | ||
|
|
4bf311d820 | ||
|
|
67b1fd9bc5 | ||
|
|
ea8a5dc25e | ||
|
|
ae5c7a3ace | ||
|
|
4b06f6b506 | ||
|
|
147cfe538a | ||
|
|
5fb6b44950 | ||
|
|
bb4c1d6181 | ||
|
|
a774ccf426 | ||
|
|
3654340e0f | ||
|
|
ee84321d4b | ||
|
|
aa49358b97 | ||
|
|
aca669defe | ||
|
|
8cad9600cc | ||
|
|
d6967a786f | ||
|
|
06e2d5b3c3 | ||
|
|
2d53ec24f8 | ||
|
|
c14ef7bee7 | ||
|
|
4299799967 | ||
|
|
c93c87de30 | ||
|
|
64045b0810 | ||
|
|
4e1aa5b946 | ||
|
|
3ce83d0cb4 | ||
|
|
f5b0e78c2f | ||
|
|
af872e4bc5 | ||
|
|
f8a82dbb90 | ||
|
|
27c5a30cc1 | ||
|
|
0541041b2b | ||
|
|
90cff01fe5 | ||
|
|
b627c6badd | ||
|
|
4f8b0dd5cc | ||
|
|
672b37c319 | ||
|
|
d0fbcffa42 | ||
|
|
8f4b028abe | ||
|
|
db7babc6ed | ||
|
|
88d516a6d4 | ||
|
|
d091458a8d | ||
|
|
c8c9db1452 | ||
|
|
10f37e0774 | ||
|
|
49583f8507 | ||
|
|
6da18c8a4f | ||
|
|
d666366deb | ||
|
|
31ac40d2cc | ||
|
|
2d0271978d | ||
|
|
13224f03cc | ||
|
|
8024f4658c | ||
|
|
beca2c99ca | ||
|
|
94b481a66f | ||
|
|
425772da1c | ||
|
|
6808d5388c | ||
|
|
e912e14cbb | ||
|
|
6e60e3dfa4 | ||
|
|
ac9dfc4f25 | ||
|
|
0369ad86a3 | ||
|
|
8d1a9f98af | ||
|
|
34c545d932 | ||
|
|
5a51225286 | ||
|
|
d2d81db8b3 | ||
|
|
90cc79b6bc | ||
|
|
ebf4425beb | ||
|
|
0daa978fba | ||
|
|
31ba45cb7a | ||
|
|
8dad6cc8db | ||
|
|
e632dea99a | ||
|
|
560f12122f | ||
|
|
3ec5d1ef3d | ||
|
|
203d735a85 | ||
|
|
35e6d54409 | ||
|
|
2c5b4c6217 | ||
|
|
94c685a5ca | ||
|
|
28e9d112c8 | ||
|
|
4698dca813 | ||
|
|
8dbf9471a6 | ||
|
|
0ef7f0155a | ||
|
|
6f0a2de505 | ||
|
|
c23eea21fc | ||
|
|
b955a37a1c | ||
|
|
df08385603 | ||
|
|
64cf11bc54 | ||
|
|
92c4c50e1c | ||
|
|
cc572729ff | ||
|
|
79a10fa18f | ||
|
|
e3b5efc9e5 | ||
|
|
ad77a438f8 | ||
|
|
a7088ce387 | ||
|
|
b06ec1f291 | ||
|
|
8eedae1af0 | ||
|
|
a3242b4823 | ||
|
|
a037a8dbe2 | ||
|
|
eb76dd5248 | ||
|
|
143067621c | ||
|
|
84d1a8983b | ||
|
|
61b71a206d | ||
|
|
ee9ff25afc | ||
|
|
5e3e8feb0a | ||
|
|
1b63a9ad80 | ||
|
|
15a99ab650 | ||
|
|
c228361654 | ||
|
|
7d644aa544 | ||
|
|
9ef0906da1 | ||
|
|
8fd6c72037 | ||
|
|
45c08db1ce | ||
|
|
7d7b2c9e2b | ||
|
|
13ce3fc6da | ||
|
|
f55f6e198a | ||
|
|
4f68cb85e1 | ||
|
|
b7f3791966 | ||
|
|
ee8dfe1ea9 | ||
|
|
6f0d5a0583 | ||
|
|
ba1637087e | ||
|
|
bdc7733faf | ||
|
|
7f4be53db0 | ||
|
|
27d998d6f2 | ||
|
|
5eb593f453 | ||
|
|
4652db0583 | ||
|
|
35d43480bf | ||
|
|
3e7c136a7f | ||
|
|
05f9f6b413 | ||
|
|
67f6eb544a | ||
|
|
3c11e934a8 | ||
|
|
627a39b8fc | ||
|
|
95c7b96dff | ||
|
|
dadd59fc3a | ||
|
|
e67d3d3666 |
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
37
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -1,37 +0,0 @@
|
||||
---
|
||||
name: Bug Report
|
||||
about: Support Requests will be closed immediately, if you are not 100% certain this is a bug please go to our Reddit or Discord first. Exceptions do not mean you found a bug!
|
||||
title: ''
|
||||
labels: 'Type: Bug'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
<!-- Support Requests will be closed immediately, if you are unsure go to our Reddit or Discord first. Exceptions do not mean you found a bug! -->
|
||||
**Describe the bug**
|
||||
<!-- A clear and concise description of what the bug is. -->
|
||||
|
||||
**To Reproduce**
|
||||
<!-- Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error -->
|
||||
|
||||
**Expected behavior**
|
||||
<!-- A clear and concise description of what you expected to happen.-->
|
||||
|
||||
**Screenshots**
|
||||
<!-- If applicable, add screenshots to help explain your problem.-->
|
||||
|
||||
**Platform Information (please complete the following information):**
|
||||
- OS: <!-- [e.g. Windows 10 2004 / Ubuntu 20.04] -->
|
||||
- Docker: <!-- [Yes/No] -->
|
||||
- Mono or .NET Version (System -> Status): <!--[e.g. Mono 5.8 or .Net Core 3.1.10 or .NET 5.0.1] -->
|
||||
- Browser and Version (Only needed for UI issues): <!--[e.g. chrome 86.0.4240.198] -->
|
||||
- Radarr Version: <!--[e.g. 3.0.1.4259, 3.0.2.4369]-->
|
||||
- Radarr Branch: <!--[e.g. master, develop]-->
|
||||
|
||||
**Trace Logs**
|
||||
Turn on Trace logs under Settings -> General and wait for the bug to occur again.
|
||||
**Upload the full log file here (or another site (e.g. pastebin) and link it). Issues will be closed, if they do not include this!**
|
||||
<!-- Trace logs are named Radarr.trace.txt or Radarr.trace.#.txt and will contain "trace" in them-->
|
||||
75
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
75
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,75 @@
|
||||
name: Bug Report
|
||||
title: "[BUG]: "
|
||||
description: 'Report a new bug, if you are not 100% certain this is a bug please go to our Reddit or Discord first'
|
||||
labels: ['Type: Bug', 'Status: Needs Triage']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the bug you encountered.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Current Behavior
|
||||
description: A concise description of what you're experiencing.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Expected Behavior
|
||||
description: A concise description of what you expected to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Steps To Reproduce
|
||||
description: Steps to reproduce the behavior.
|
||||
placeholder: |
|
||||
1. In this environment...
|
||||
2. With this config...
|
||||
3. Run '...'
|
||||
4. See error...
|
||||
validations:
|
||||
required: false
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Environment
|
||||
description: |
|
||||
examples:
|
||||
- **OS**: Ubuntu 20.04
|
||||
- **Radarr**: Radarr 3.0.1.4259
|
||||
- **Docker Install**: Yes
|
||||
- **Using Reverse Proxy**: No
|
||||
- **Browser**: Firefox 90 (If UI related)
|
||||
value: |
|
||||
- OS:
|
||||
- Radarr:
|
||||
- Docker Install:
|
||||
- Using Reverse Proxy:
|
||||
- Browser:
|
||||
render: markdown
|
||||
validations:
|
||||
required: true
|
||||
- type: dropdown
|
||||
attributes:
|
||||
label: What branch are you running?
|
||||
options:
|
||||
- Master
|
||||
- Develop
|
||||
- Nightly
|
||||
- Other (This issue will be closed)
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Trace Logs (https://wiki.servarr.com/radarr/troubleshooting#logging-and-log-files)
|
||||
Links? References? Anything that will give us more context about the issue you are encountering!
|
||||
***Generally speaking, all bug reports must have trace logs provided.***
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: true
|
||||
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
20
.github/ISSUE_TEMPLATE/feature_request.md
vendored
@@ -1,20 +0,0 @@
|
||||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: feature request
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
<!-- A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] -->
|
||||
|
||||
**Describe the solution you'd like**
|
||||
<!-- A clear and concise description of what you want to happen. -->
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
<!-- A clear and concise description of any alternative solutions or features you've considered. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
39
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
39
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,39 @@
|
||||
name: Feature Request
|
||||
title: "[FEAT]: "
|
||||
description: 'Suggest an idea for Radarr'
|
||||
labels: ['Type: Feature Request', 'Status: Needs Triage']
|
||||
body:
|
||||
- type: checkboxes
|
||||
attributes:
|
||||
label: Is there an existing issue for this?
|
||||
description: Please search to see if an issue already exists for the feature you are requesting.
|
||||
options:
|
||||
- label: I have searched the existing issues
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Is your feature request related to a problem? Please describe
|
||||
description: A clear and concise description of what the problem is.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe the solution you'd like
|
||||
description: A clear and concise description of what you want to happen.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Describe alternatives you've considered
|
||||
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||
validations:
|
||||
required: true
|
||||
- type: textarea
|
||||
attributes:
|
||||
label: Anything else?
|
||||
description: |
|
||||
Links? References? Mockups? Anything that will give us more context about the feature you are encountering!
|
||||
|
||||
Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in.
|
||||
validations:
|
||||
required: true
|
||||
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
9
.github/PULL_REQUEST_TEMPLATE.md
vendored
@@ -1,15 +1,16 @@
|
||||
#### Database Migration
|
||||
YES | NO
|
||||
YES - XXXX | NO
|
||||
|
||||
#### Description
|
||||
A few sentences describing the overall goals of the pull request's commits.
|
||||
|
||||
#### Screenshot (if UI related)
|
||||
|
||||
#### Todos
|
||||
- [ ] Tests
|
||||
- [ ] Translation Keys
|
||||
- [ ] Wiki Updates
|
||||
- [ ] Translation Keys (./src/NzbDrone.Core/Localization/Core/en.json)
|
||||
- [ ] [Wiki Updates](https://wiki.servarr.com)
|
||||
|
||||
#### Issues Fixed or Closed by this PR
|
||||
|
||||
* Fixes #XXXX
|
||||
* Fixes #XXXX
|
||||
3
.github/stale.yml
vendored
3
.github/stale.yml
vendored
@@ -4,7 +4,8 @@ daysUntilStale: 60
|
||||
daysUntilClose: 7
|
||||
# Issues with these labels will never be considered stale
|
||||
exemptLabels:
|
||||
- feature request
|
||||
- feature request #legacy
|
||||
- 'Type: Feature Request'
|
||||
- 'Status: Confirmed'
|
||||
- sonarr-pull
|
||||
- lidarr-pull
|
||||
|
||||
41
.github/workflows/azuresync.yml
vendored
Normal file
41
.github/workflows/azuresync.yml
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
name: Sync issue to Azure DevOps work item
|
||||
|
||||
on:
|
||||
issues:
|
||||
types:
|
||||
[opened, edited, deleted, closed, reopened, labeled, unlabeled, assigned]
|
||||
|
||||
concurrency: azuresync-${{ github.event.issue.number }}
|
||||
|
||||
jobs:
|
||||
alert:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: danhellem/github-actions-issue-to-work-item@master
|
||||
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == true }}"
|
||||
env:
|
||||
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
|
||||
github_token: "${{ github.token }}"
|
||||
ado_organization: "Servarr"
|
||||
ado_project: "Servarr"
|
||||
ado_area_path: "Servarr\\Radarr"
|
||||
ado_wit: "Bug"
|
||||
ado_new_state: "New"
|
||||
ado_active_state: "Active"
|
||||
ado_close_state: "Closed"
|
||||
ado_bypassrules: true
|
||||
log_level: 100
|
||||
- uses: danhellem/github-actions-issue-to-work-item@master
|
||||
if: "${{ contains(github.event.issue.labels.*.name, 'Type: Bug') == false }}"
|
||||
env:
|
||||
ado_token: "${{ secrets.ADO_PERSONAL_ACCESS_TOKEN }}"
|
||||
github_token: "${{ github.token }}"
|
||||
ado_organization: "Servarr"
|
||||
ado_project: "Servarr"
|
||||
ado_area_path: "Servarr\\Radarr"
|
||||
ado_wit: "User Story"
|
||||
ado_new_state: "New"
|
||||
ado_active_state: "Active"
|
||||
ado_close_state: "Closed"
|
||||
ado_bypassrules: true
|
||||
log_level: 100
|
||||
@@ -1,49 +1,13 @@
|
||||
# How to Contribute #
|
||||
# How to Contribute
|
||||
|
||||
We're always looking for people to help make Radarr even better, there are a number of ways to contribute.
|
||||
|
||||
## Documentation ##
|
||||
Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/Radarr) the better.
|
||||
This file has been moved to the wiki for the latest details please see the [contributing wiki page](https://wiki.servarr.com/radarr/contributing).
|
||||
|
||||
## Development ##
|
||||
## Documentation
|
||||
|
||||
### Tools required ###
|
||||
- Visual Studio 2019 or higher (https://www.visualstudio.com/vs/). The community version is free and works (https://www.visualstudio.com/downloads/).
|
||||
- HTML/Javascript editor of choice (VS Code/Sublime Text/Webstorm/Atom/etc)
|
||||
- [Git](https://git-scm.com/downloads)
|
||||
- [NodeJS](https://nodejs.org/en/download/) (Node 12.X.X or higher)
|
||||
- [Yarn](https://yarnpkg.com/)
|
||||
- .NET Core 5.0.
|
||||
Setup guides, [FAQ](https://wiki.servarr.com/radarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/radarr) the better.
|
||||
|
||||
### Getting started ###
|
||||
## Development
|
||||
|
||||
1. Fork Radarr
|
||||
2. Clone the repository into your development machine. [*info*](https://docs.github.com/en/github/creating-cloning-and-archiving-repositories/cloning-a-repository-from-github)
|
||||
3. Install the required Node Packages `yarn install`
|
||||
4. Start gulp to monitor your dev environment for any changes that need post processing using `yarn start` command.
|
||||
5. Build the project in Visual Studio, Setting startup project to `Radarr.Console` and framework to `net5.0`
|
||||
6. Debug the project in Visual Studio
|
||||
7. Open http://localhost:7878
|
||||
|
||||
### Contributing Code ###
|
||||
- If you're adding a new, already requested feature, please comment on [Github Issues](https://github.com/Radarr/Radarr/issues "Github Issues") so work is not duplicated (If you want to add something not already on there, please talk to us first)
|
||||
- Rebase from Radarr's develop branch, don't merge
|
||||
- Make meaningful commits, or squash them
|
||||
- Feel free to make a pull request before work is complete, this will let us see where its at and make comments/suggest improvements
|
||||
- Reach out to us on the discord if you have any questions
|
||||
- Add tests (unit/integration)
|
||||
- Commit with *nix line endings for consistency (We checkout Windows and commit *nix)
|
||||
- One feature/bug fix per pull request to keep things clean and easy to understand
|
||||
- Use 4 spaces instead of tabs, this is the default for VS 2019 and WebStorm (to my knowledge)
|
||||
|
||||
### Pull Requesting ###
|
||||
- Only make pull requests to develop, never master, if you make a PR to master we'll comment on it and close it
|
||||
- You're probably going to get some comments or questions from us, they will be to ensure consistency and maintainability
|
||||
- We'll try to respond to pull requests as soon as possible, if its been a day or two, please reach out to us, we may have missed it
|
||||
- Each PR should come from its own [feature branch](http://martinfowler.com/bliki/FeatureBranch.html) not develop in your fork, it should have a meaningful branch name (what is being added/fixed)
|
||||
- new-feature (Good)
|
||||
- fix-bug (Good)
|
||||
- patch (Bad)
|
||||
- develop (Bad)
|
||||
|
||||
If you have any questions about any of this, please let us know.
|
||||
See the [Wiki Page](https://wiki.servarr.com/radarr/contributing)
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
[](https://dev.azure.com/Radarr/Radarr/_build/latest?definitionId=1&branchName=develop)
|
||||
[](https://translate.servarr.com/engage/radarr/?utm_source=widget)
|
||||
[](https://wiki.servarr.com/Radarr_Installation#Docker)
|
||||
[](https://wiki.servarr.com/radarr/installation#docker)
|
||||

|
||||
[](#backers)
|
||||
[](#sponsors)
|
||||
@@ -34,11 +34,7 @@ Note: GitHub Issues are for Bugs and Feature Requests Only
|
||||
[](https://radarr.video/discord)
|
||||
[](https://www.reddit.com/r/Radarr)
|
||||
[](https://github.com/Radarr/Radarr/issues)
|
||||
[](https://wiki.servarr.com/Radarr)
|
||||
|
||||
## Feature Requests
|
||||
|
||||
[Feature Requests](https://github.com/Radarr/Radarr/issues/new?assignees=&labels=Type%3A+Enhancement&template=feature_request.md&title=)
|
||||
[](https://wiki.servarr.com/radarr)
|
||||
|
||||
## Contributors & Developers
|
||||
[API Documentation](https://radarr.video/docs/api/)
|
||||
|
||||
@@ -7,13 +7,13 @@ variables:
|
||||
outputFolder: './_output'
|
||||
artifactsFolder: './_artifacts'
|
||||
testsFolder: './_tests'
|
||||
majorVersion: '3.2.0'
|
||||
majorVersion: '4.0.0'
|
||||
minorVersion: $[counter('minorVersion', 2000)]
|
||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||
sentryOrg: 'servarr'
|
||||
sentryUrl: 'https://sentry.servarr.com'
|
||||
dotnetVersion: '5.0.202'
|
||||
dotnetVersion: '5.0.401'
|
||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||
|
||||
trigger:
|
||||
@@ -67,7 +67,7 @@ stages:
|
||||
enableAnalysis: 'true'
|
||||
Mac:
|
||||
osName: 'Mac'
|
||||
imageName: 'macos-10.14'
|
||||
imageName: 'macos-10.15'
|
||||
enableAnalysis: 'false'
|
||||
Windows:
|
||||
osName: 'Windows'
|
||||
@@ -115,10 +115,6 @@ stages:
|
||||
artifact: WindowsCoreTests
|
||||
displayName: Publish Windows Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net472/linux-x64/publish'
|
||||
artifact: LinuxTests
|
||||
displayName: Publish Linux Mono Test Package
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- publish: '$(testsFolder)/net5.0/linux-x64/publish'
|
||||
artifact: LinuxCoreTests
|
||||
displayName: Publish Linux Test Package
|
||||
@@ -148,7 +144,7 @@ stages:
|
||||
imageName: 'ubuntu-18.04'
|
||||
Mac:
|
||||
osName: 'Mac'
|
||||
imageName: 'macos-10.14'
|
||||
imageName: 'macos-10.15'
|
||||
Windows:
|
||||
osName: 'Windows'
|
||||
imageName: 'windows-2019'
|
||||
@@ -245,6 +241,7 @@ stages:
|
||||
- bash: ./build.sh --packages --enable-bsd
|
||||
displayName: Create Packages
|
||||
- bash: |
|
||||
find . -name "ffprobe" -exec chmod a+x {} \;
|
||||
find . -name "Radarr" -exec chmod a+x {} \;
|
||||
find . -name "Radarr.Update" -exec chmod a+x {} \;
|
||||
displayName: Set executable bits
|
||||
@@ -277,14 +274,6 @@ stages:
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/macos/net5.0
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create Linux Mono tar
|
||||
inputs:
|
||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).linux.tar.gz'
|
||||
archiveType: 'tar'
|
||||
tarCompression: 'gz'
|
||||
includeRootFolder: false
|
||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/net472
|
||||
- task: ArchiveFiles@2
|
||||
displayName: Create Linux Core tar
|
||||
inputs:
|
||||
@@ -395,7 +384,7 @@ stages:
|
||||
osName: 'Mac'
|
||||
testName: 'MacCore'
|
||||
poolName: 'Azure Pipelines'
|
||||
imageName: 'macos-10.14'
|
||||
imageName: 'macos-10.15'
|
||||
WindowsCore:
|
||||
osName: 'Windows'
|
||||
testName: 'WindowsCore'
|
||||
@@ -429,24 +418,13 @@ stages:
|
||||
buildType: 'current'
|
||||
artifactName: '$(testName)Tests'
|
||||
targetPath: $(testsFolder)
|
||||
- bash: |
|
||||
wget https://mediaarea.net/repo/deb/repo-mediaarea_1.0-11_all.deb
|
||||
sudo dpkg -i repo-mediaarea_1.0-11_all.deb
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y --allow-unauthenticated libmediainfo-dev libmediainfo0v5 mediainfo
|
||||
displayName: Install mediainfo
|
||||
condition: and(succeeded(), eq(variables['testName'], 'LinuxCore'))
|
||||
- powershell: Set-Service SCardSvr -StartupType Manual
|
||||
displayName: Enable Windows Test Service
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||
- bash: |
|
||||
SYMLINK=6_6_0
|
||||
MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK
|
||||
echo "##vso[task.setvariable variable=MONOPREFIX;]$MONOPREFIX"
|
||||
echo "##vso[task.setvariable variable=PKG_CONFIG_PATH;]$MONOPREFIX/lib/pkgconfig:$MONOPREFIX/share/pkgconfig:$PKG_CONFIG_PATH"
|
||||
echo "##vso[task.setvariable variable=PATH;]$MONOPREFIX/bin:$PATH"
|
||||
displayName: Set Mono Version
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Mac'))
|
||||
chmod a+x _tests/ffprobe
|
||||
displayName: Make ffprobe Executable
|
||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
||||
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
||||
displayName: Make Test Dummy Executable
|
||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
||||
@@ -470,18 +448,6 @@ stages:
|
||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||
strategy:
|
||||
matrix:
|
||||
mono520:
|
||||
testName: 'Mono 5.20'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-5.20
|
||||
mono610:
|
||||
testName: 'Mono 6.10'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-6.10
|
||||
mono612:
|
||||
testName: 'Mono 6.12'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-6.12
|
||||
alpine:
|
||||
testName: 'Musl Net Core'
|
||||
artifactName: LinuxMuslCoreTests
|
||||
@@ -506,6 +472,9 @@ stages:
|
||||
buildType: 'current'
|
||||
artifactName: $(artifactName)
|
||||
targetPath: $(testsFolder)
|
||||
- bash: |
|
||||
chmod a+x _tests/ffprobe
|
||||
displayName: Make ffprobe Executable
|
||||
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
||||
displayName: Make Test Dummy Executable
|
||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
||||
@@ -549,7 +518,7 @@ stages:
|
||||
MacCore:
|
||||
osName: 'Mac'
|
||||
testName: 'MacCore'
|
||||
imageName: 'macos-10.14'
|
||||
imageName: 'macos-10.15'
|
||||
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
||||
WindowsCore:
|
||||
osName: 'Windows'
|
||||
@@ -566,14 +535,6 @@ stages:
|
||||
vmImage: $(imageName)
|
||||
|
||||
steps:
|
||||
- bash: |
|
||||
SYMLINK=6_6_0
|
||||
MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK
|
||||
echo "##vso[task.setvariable variable=MONOPREFIX;]$MONOPREFIX"
|
||||
echo "##vso[task.setvariable variable=PKG_CONFIG_PATH;]$MONOPREFIX/lib/pkgconfig:$MONOPREFIX/share/pkgconfig:$PKG_CONFIG_PATH"
|
||||
echo "##vso[task.setvariable variable=PATH;]$MONOPREFIX/bin:$PATH"
|
||||
displayName: Set Mono Version
|
||||
condition: and(succeeded(), eq(variables['osName'], 'Mac'))
|
||||
- task: UseDotNet@2
|
||||
displayName: 'Install .net core'
|
||||
inputs:
|
||||
@@ -665,21 +626,6 @@ stages:
|
||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||
strategy:
|
||||
matrix:
|
||||
mono520:
|
||||
testName: 'Mono 5.20'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-5.20
|
||||
pattern: 'Radarr.*.linux.tar.gz'
|
||||
mono610:
|
||||
testName: 'Mono 6.10'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-6.10
|
||||
pattern: 'Radarr.*.linux.tar.gz'
|
||||
mono612:
|
||||
testName: 'Mono 6.12'
|
||||
artifactName: LinuxTests
|
||||
containerImage: ghcr.io/servarr/testimages:mono-6.12
|
||||
pattern: 'Radarr.*.linux.tar.gz'
|
||||
alpine:
|
||||
testName: 'Musl Net Core'
|
||||
artifactName: LinuxMuslCoreTests
|
||||
@@ -747,7 +693,7 @@ stages:
|
||||
failBuild: true
|
||||
Mac:
|
||||
osName: 'Mac'
|
||||
imageName: 'macos-10.14'
|
||||
imageName: 'macos-10.15'
|
||||
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
||||
failBuild: true
|
||||
Windows:
|
||||
@@ -916,7 +862,7 @@ stages:
|
||||
projectVersion: '$(radarrVersion)'
|
||||
extraProperties: |
|
||||
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
|
||||
sonar.coverage.exclusions=**/Radarr.Api.V3/**/*,**/NzbDrone.Api/**/*,**/MonoTorrent/**/*,**/Marr.Data/**/*
|
||||
sonar.coverage.exclusions=**/Radarr.Api.V3/**/*
|
||||
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
||||
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
||||
- bash: |
|
||||
@@ -951,7 +897,7 @@ stages:
|
||||
- job:
|
||||
displayName: Discord Notification
|
||||
pool:
|
||||
vmImage: 'windows-2019'
|
||||
vmImage: 'ubuntu-18.04'
|
||||
steps:
|
||||
- task: DownloadPipelineArtifact@2
|
||||
continueOnError: true
|
||||
@@ -961,7 +907,7 @@ stages:
|
||||
artifactName: 'WindowsAutomationScreenshots'
|
||||
targetPath: $(Build.SourcesDirectory)
|
||||
- checkout: none
|
||||
- powershell: |
|
||||
- pwsh: |
|
||||
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Servarr/AzureDiscordNotify/master/DiscordNotify.ps1'))
|
||||
env:
|
||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||
|
||||
8
build.sh
8
build.sh
@@ -33,7 +33,6 @@ EnableBsdSupport()
|
||||
|
||||
if grep -qv freebsd-x64 src/Directory.Build.props; then
|
||||
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
|
||||
sed -i'' -e "s^<ExcludedRuntimeFrameworkPairs>\(.*\)</ExcludedRuntimeFrameworkPairs>^<ExcludedRuntimeFrameworkPairs>\1;freebsd-x64:net472</ExcludedRuntimeFrameworkPairs>^g" src/Directory.Build.props
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -148,11 +147,6 @@ PackageMacOS()
|
||||
|
||||
PackageFiles "$folder" "$framework" "osx-x64"
|
||||
|
||||
if [ "$framework" = "net472" ]; then
|
||||
echo "Adding Startup script"
|
||||
cp macOS/Radarr $folder
|
||||
fi
|
||||
|
||||
echo "Removing Service helpers"
|
||||
rm -f $folder/ServiceUninstall.*
|
||||
rm -f $folder/ServiceInstall.*
|
||||
@@ -337,7 +331,6 @@ then
|
||||
PackageTests "net5.0" "linux-x64"
|
||||
PackageTests "net5.0" "linux-musl-x64"
|
||||
PackageTests "net5.0" "osx-x64"
|
||||
PackageTests "net472" "linux-x64"
|
||||
if [ "$ENABLE_BSD" = "YES" ];
|
||||
then
|
||||
PackageTests "net5.0" "freebsd-x64"
|
||||
@@ -377,7 +370,6 @@ then
|
||||
Package "net5.0" "linux-musl-arm64"
|
||||
Package "net5.0" "linux-arm"
|
||||
Package "net5.0" "osx-x64"
|
||||
Package "net472" "linux-x64"
|
||||
if [ "$ENABLE_BSD" = "YES" ];
|
||||
then
|
||||
Package "net5.0" "freebsd-x64"
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
],
|
||||
"ignoreFiles": [
|
||||
"frontend/src/Styles/scaffolding.css",
|
||||
"**/Theme.Park/**/*.css",
|
||||
"**/*.js"
|
||||
],
|
||||
"rules": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
const path = require('path');
|
||||
const webpack = require('webpack');
|
||||
const CopyPlugin = require('copy-webpack-plugin');
|
||||
const FileManagerPlugin = require('filemanager-webpack-plugin');
|
||||
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||
const LiveReloadPlugin = require('webpack-livereload-plugin');
|
||||
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||
@@ -23,7 +23,7 @@ module.exports = (env) => {
|
||||
|
||||
const config = {
|
||||
mode: isProduction ? 'production' : 'development',
|
||||
devtool: 'source-map',
|
||||
devtool: isProduction ? 'source-map' : 'eval-source-map',
|
||||
|
||||
stats: {
|
||||
children: false
|
||||
@@ -87,46 +87,61 @@ module.exports = (env) => {
|
||||
}),
|
||||
|
||||
new HtmlWebpackPlugin({
|
||||
template: 'frontend/src/index.html',
|
||||
template: 'frontend/src/index.ejs',
|
||||
filename: 'index.html',
|
||||
publicPath: '/'
|
||||
}),
|
||||
|
||||
new CopyPlugin({
|
||||
patterns: [
|
||||
// HTML
|
||||
{
|
||||
from: 'frontend/src/*.html',
|
||||
to: path.join(distFolder, '[name][ext]'),
|
||||
globOptions: {
|
||||
ignore: ['**/index.html']
|
||||
}
|
||||
},
|
||||
new FileManagerPlugin({
|
||||
events: {
|
||||
onEnd: {
|
||||
copy: [
|
||||
// HTML
|
||||
{
|
||||
source: 'frontend/src/*.html',
|
||||
destination: distFolder
|
||||
},
|
||||
|
||||
// Fonts
|
||||
{
|
||||
from: 'frontend/src/Content/Fonts/*.*',
|
||||
to: path.join(distFolder, 'Content/Fonts', '[name][ext]')
|
||||
},
|
||||
// Fonts
|
||||
{
|
||||
source: 'frontend/src/Content/Fonts/*.*',
|
||||
destination: path.join(distFolder, 'Content/Fonts')
|
||||
},
|
||||
|
||||
// Icon Images
|
||||
{
|
||||
from: 'frontend/src/Content/Images/Icons/*.*',
|
||||
to: path.join(distFolder, 'Content/Images/Icons', '[name][ext]')
|
||||
},
|
||||
// Icon Images
|
||||
{
|
||||
source: 'frontend/src/Content/Images/Icons/*.*',
|
||||
destination: path.join(distFolder, 'Content/Images/Icons')
|
||||
},
|
||||
|
||||
// Images
|
||||
{
|
||||
from: 'frontend/src/Content/Images/*.*',
|
||||
to: path.join(distFolder, 'Content/Images', '[name][ext]')
|
||||
},
|
||||
// Images
|
||||
{
|
||||
source: 'frontend/src/Content/Images/*.*',
|
||||
destination: path.join(distFolder, 'Content/Images')
|
||||
},
|
||||
|
||||
// Robots
|
||||
{
|
||||
from: 'frontend/src/Content/robots.txt',
|
||||
to: path.join(distFolder, 'Content', '[name][ext]')
|
||||
// Robots
|
||||
{
|
||||
source: 'frontend/src/Content/robots.txt',
|
||||
destination: path.join(distFolder, 'Content/robots.txt')
|
||||
},
|
||||
|
||||
// Theme.Park
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park')
|
||||
},
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/Themes/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park/Themes')
|
||||
},
|
||||
{
|
||||
source: 'frontend/src/Content/Theme.Park/Resources/*',
|
||||
destination: path.join(distFolder, 'Content/Theme.Park/Resources')
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}),
|
||||
|
||||
new LiveReloadPlugin()
|
||||
@@ -242,6 +257,19 @@ module.exports = (env) => {
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
{
|
||||
test: /\.(png)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
emitFile: false,
|
||||
name: 'Content/Theme.Park/Resources/[name].[ext]'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,160 +0,0 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import * as blacklistActions from 'Store/Actions/blacklistActions';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import Blacklist from './Blacklist';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.blacklist,
|
||||
createCommandExecutingSelector(commandNames.CLEAR_BLACKLIST),
|
||||
(blacklist, isClearingBlacklistExecuting) => {
|
||||
return {
|
||||
isClearingBlacklistExecuting,
|
||||
...blacklist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
...blacklistActions,
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class BlacklistConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
useCurrentPage,
|
||||
fetchBlacklist,
|
||||
gotoBlacklistFirstPage
|
||||
} = this.props;
|
||||
|
||||
registerPagePopulator(this.repopulate);
|
||||
|
||||
if (useCurrentPage) {
|
||||
fetchBlacklist();
|
||||
} else {
|
||||
gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.isClearingBlacklistExecuting && !this.props.isClearingBlacklistExecuting) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearBlacklist();
|
||||
unregisterPagePopulator(this.repopulate);
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
repopulate = () => {
|
||||
this.props.fetchBlacklist();
|
||||
}
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFirstPagePress = () => {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
|
||||
onPreviousPagePress = () => {
|
||||
this.props.gotoBlacklistPreviousPage();
|
||||
}
|
||||
|
||||
onNextPagePress = () => {
|
||||
this.props.gotoBlacklistNextPage();
|
||||
}
|
||||
|
||||
onLastPagePress = () => {
|
||||
this.props.gotoBlacklistLastPage();
|
||||
}
|
||||
|
||||
onPageSelect = (page) => {
|
||||
this.props.gotoBlacklistPage({ page });
|
||||
}
|
||||
|
||||
onRemoveSelected = (ids) => {
|
||||
this.props.removeBlacklistItems({ ids });
|
||||
}
|
||||
|
||||
onSortPress = (sortKey) => {
|
||||
this.props.setBlacklistSort({ sortKey });
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlacklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
onClearBlacklistPress = () => {
|
||||
this.props.executeCommand({ name: commandNames.CLEAR_BLACKLIST });
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlacklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlacklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Blacklist
|
||||
onFirstPagePress={this.onFirstPagePress}
|
||||
onPreviousPagePress={this.onPreviousPagePress}
|
||||
onNextPagePress={this.onNextPagePress}
|
||||
onLastPagePress={this.onLastPagePress}
|
||||
onPageSelect={this.onPageSelect}
|
||||
onRemoveSelected={this.onRemoveSelected}
|
||||
onSortPress={this.onSortPress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onClearBlacklistPress={this.onClearBlacklistPress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistConnector.propTypes = {
|
||||
useCurrentPage: PropTypes.bool.isRequired,
|
||||
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchBlacklist: PropTypes.func.isRequired,
|
||||
gotoBlacklistFirstPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistPreviousPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistNextPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistLastPage: PropTypes.func.isRequired,
|
||||
gotoBlacklistPage: PropTypes.func.isRequired,
|
||||
removeBlacklistItems: PropTypes.func.isRequired,
|
||||
setBlacklistSort: PropTypes.func.isRequired,
|
||||
setBlacklistTableOption: PropTypes.func.isRequired,
|
||||
clearBlacklist: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default withCurrentPage(
|
||||
connect(createMapStateToProps, mapDispatchToProps)(BlacklistConnector)
|
||||
);
|
||||
@@ -19,9 +19,9 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
import BlacklistRowConnector from './BlacklistRowConnector';
|
||||
import BlocklistRowConnector from './BlocklistRowConnector';
|
||||
|
||||
class Blacklist extends Component {
|
||||
class Blocklist extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -101,8 +101,8 @@ class Blacklist extends Component {
|
||||
columns,
|
||||
totalRecords,
|
||||
isRemoving,
|
||||
isClearingBlacklistExecuting,
|
||||
onClearBlacklistPress,
|
||||
isClearingBlocklistExecuting,
|
||||
onClearBlocklistPress,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
@@ -116,7 +116,7 @@ class Blacklist extends Component {
|
||||
const selectedIds = this.getSelectedIds();
|
||||
|
||||
return (
|
||||
<PageContent title={translate('Blacklist')}>
|
||||
<PageContent title={translate('Blocklist')}>
|
||||
<PageToolbar>
|
||||
<PageToolbarSection>
|
||||
<PageToolbarButton
|
||||
@@ -130,8 +130,8 @@ class Blacklist extends Component {
|
||||
<PageToolbarButton
|
||||
label={translate('Clear')}
|
||||
iconName={icons.CLEAR}
|
||||
isSpinning={isClearingBlacklistExecuting}
|
||||
onPress={onClearBlacklistPress}
|
||||
isSpinning={isClearingBlocklistExecuting}
|
||||
onPress={onClearBlocklistPress}
|
||||
/>
|
||||
</PageToolbarSection>
|
||||
|
||||
@@ -157,7 +157,7 @@ class Blacklist extends Component {
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
{translate('UnableToLoadBlacklist')}
|
||||
{translate('UnableToLoadBlocklist')}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -183,7 +183,7 @@ class Blacklist extends Component {
|
||||
{
|
||||
items.map((item) => {
|
||||
return (
|
||||
<BlacklistRowConnector
|
||||
<BlocklistRowConnector
|
||||
key={item.id}
|
||||
isSelected={selectedState[item.id] || false}
|
||||
columns={columns}
|
||||
@@ -209,7 +209,7 @@ class Blacklist extends Component {
|
||||
isOpen={isConfirmRemoveModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('RemoveSelected')}
|
||||
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlacklist')}
|
||||
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist')}
|
||||
confirmLabel={translate('RemoveSelected')}
|
||||
onConfirm={this.onRemoveSelectedConfirmed}
|
||||
onCancel={this.onConfirmRemoveModalClose}
|
||||
@@ -219,7 +219,7 @@ class Blacklist extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
Blacklist.propTypes = {
|
||||
Blocklist.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
@@ -227,9 +227,9 @@ Blacklist.propTypes = {
|
||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
totalRecords: PropTypes.number,
|
||||
isRemoving: PropTypes.bool.isRequired,
|
||||
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
|
||||
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
|
||||
onRemoveSelected: PropTypes.func.isRequired,
|
||||
onClearBlacklistPress: PropTypes.func.isRequired
|
||||
onClearBlocklistPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default Blacklist;
|
||||
export default Blocklist;
|
||||
152
frontend/src/Activity/Blocklist/BlocklistConnector.js
Normal file
152
frontend/src/Activity/Blocklist/BlocklistConnector.js
Normal file
@@ -0,0 +1,152 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import * as commandNames from 'Commands/commandNames';
|
||||
import withCurrentPage from 'Components/withCurrentPage';
|
||||
import * as blocklistActions from 'Store/Actions/blocklistActions';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createCommandExecutingSelector from 'Store/Selectors/createCommandExecutingSelector';
|
||||
import { registerPagePopulator, unregisterPagePopulator } from 'Utilities/pagePopulator';
|
||||
import Blocklist from './Blocklist';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state) => state.blocklist,
|
||||
createCommandExecutingSelector(commandNames.CLEAR_BLOCKLIST),
|
||||
(blocklist, isClearingBlocklistExecuting) => {
|
||||
return {
|
||||
isClearingBlocklistExecuting,
|
||||
...blocklist
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
const mapDispatchToProps = {
|
||||
...blocklistActions,
|
||||
executeCommand
|
||||
};
|
||||
|
||||
class BlocklistConnector extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
|
||||
componentDidMount() {
|
||||
const {
|
||||
useCurrentPage,
|
||||
fetchBlocklist,
|
||||
gotoBlocklistFirstPage
|
||||
} = this.props;
|
||||
|
||||
registerPagePopulator(this.repopulate);
|
||||
|
||||
if (useCurrentPage) {
|
||||
fetchBlocklist();
|
||||
} else {
|
||||
gotoBlocklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevProps) {
|
||||
if (prevProps.isClearingBlocklistExecuting && !this.props.isClearingBlocklistExecuting) {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.props.clearBlocklist();
|
||||
unregisterPagePopulator(this.repopulate);
|
||||
}
|
||||
|
||||
//
|
||||
// Control
|
||||
|
||||
repopulate = () => {
|
||||
this.props.fetchBlocklist();
|
||||
}
|
||||
//
|
||||
// Listeners
|
||||
|
||||
onFirstPagePress = () => {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
}
|
||||
|
||||
onPreviousPagePress = () => {
|
||||
this.props.gotoBlocklistPreviousPage();
|
||||
}
|
||||
|
||||
onNextPagePress = () => {
|
||||
this.props.gotoBlocklistNextPage();
|
||||
}
|
||||
|
||||
onLastPagePress = () => {
|
||||
this.props.gotoBlocklistLastPage();
|
||||
}
|
||||
|
||||
onPageSelect = (page) => {
|
||||
this.props.gotoBlocklistPage({ page });
|
||||
}
|
||||
|
||||
onRemoveSelected = (ids) => {
|
||||
this.props.removeBlocklistItems({ ids });
|
||||
}
|
||||
|
||||
onSortPress = (sortKey) => {
|
||||
this.props.setBlocklistSort({ sortKey });
|
||||
}
|
||||
|
||||
onTableOptionChange = (payload) => {
|
||||
this.props.setBlocklistTableOption(payload);
|
||||
|
||||
if (payload.pageSize) {
|
||||
this.props.gotoBlocklistFirstPage();
|
||||
}
|
||||
}
|
||||
|
||||
onClearBlocklistPress = () => {
|
||||
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
|
||||
}
|
||||
|
||||
//
|
||||
// Render
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Blocklist
|
||||
onFirstPagePress={this.onFirstPagePress}
|
||||
onPreviousPagePress={this.onPreviousPagePress}
|
||||
onNextPagePress={this.onNextPagePress}
|
||||
onLastPagePress={this.onLastPagePress}
|
||||
onPageSelect={this.onPageSelect}
|
||||
onRemoveSelected={this.onRemoveSelected}
|
||||
onSortPress={this.onSortPress}
|
||||
onTableOptionChange={this.onTableOptionChange}
|
||||
onClearBlocklistPress={this.onClearBlocklistPress}
|
||||
{...this.props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
BlocklistConnector.propTypes = {
|
||||
useCurrentPage: PropTypes.bool.isRequired,
|
||||
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
fetchBlocklist: PropTypes.func.isRequired,
|
||||
gotoBlocklistFirstPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistPreviousPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistNextPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistLastPage: PropTypes.func.isRequired,
|
||||
gotoBlocklistPage: PropTypes.func.isRequired,
|
||||
removeBlocklistItems: PropTypes.func.isRequired,
|
||||
setBlocklistSort: PropTypes.func.isRequired,
|
||||
setBlocklistTableOption: PropTypes.func.isRequired,
|
||||
clearBlocklist: PropTypes.func.isRequired,
|
||||
executeCommand: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default withCurrentPage(
|
||||
connect(createMapStateToProps, mapDispatchToProps)(BlocklistConnector)
|
||||
);
|
||||
@@ -10,7 +10,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import translate from 'Utilities/String/translate';
|
||||
|
||||
class BlacklistDetailsModal extends Component {
|
||||
class BlocklistDetailsModal extends Component {
|
||||
|
||||
//
|
||||
// Render
|
||||
@@ -78,7 +78,7 @@ class BlacklistDetailsModal extends Component {
|
||||
}
|
||||
}
|
||||
|
||||
BlacklistDetailsModal.propTypes = {
|
||||
BlocklistDetailsModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
protocol: PropTypes.string.isRequired,
|
||||
@@ -87,4 +87,4 @@ BlacklistDetailsModal.propTypes = {
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlacklistDetailsModal;
|
||||
export default BlocklistDetailsModal;
|
||||
@@ -11,10 +11,10 @@ import MovieLanguage from 'Movie/MovieLanguage';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
import MovieTitleLink from 'Movie/MovieTitleLink';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
||||
import styles from './BlacklistRow.css';
|
||||
import BlocklistDetailsModal from './BlocklistDetailsModal';
|
||||
import styles from './BlocklistRow.css';
|
||||
|
||||
class BlacklistRow extends Component {
|
||||
class BlocklistRow extends Component {
|
||||
|
||||
//
|
||||
// Lifecycle
|
||||
@@ -166,7 +166,7 @@ class BlacklistRow extends Component {
|
||||
/>
|
||||
|
||||
<IconButton
|
||||
title={translate('RemoveFromBlacklist')}
|
||||
title={translate('RemoveFromBlocklist')}
|
||||
name={icons.REMOVE}
|
||||
kind={kinds.DANGER}
|
||||
onPress={onRemovePress}
|
||||
@@ -179,7 +179,7 @@ class BlacklistRow extends Component {
|
||||
})
|
||||
}
|
||||
|
||||
<BlacklistDetailsModal
|
||||
<BlocklistDetailsModal
|
||||
isOpen={this.state.isDetailsModalOpen}
|
||||
sourceTitle={sourceTitle}
|
||||
protocol={protocol}
|
||||
@@ -193,7 +193,7 @@ class BlacklistRow extends Component {
|
||||
|
||||
}
|
||||
|
||||
BlacklistRow.propTypes = {
|
||||
BlocklistRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
movie: PropTypes.object.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
@@ -210,4 +210,4 @@ BlacklistRow.propTypes = {
|
||||
onRemovePress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default BlacklistRow;
|
||||
export default BlocklistRow;
|
||||
@@ -1,8 +1,8 @@
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { removeBlacklistItem } from 'Store/Actions/blacklistActions';
|
||||
import { removeBlocklistItem } from 'Store/Actions/blocklistActions';
|
||||
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
||||
import BlacklistRow from './BlacklistRow';
|
||||
import BlocklistRow from './BlocklistRow';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
@@ -18,9 +18,9 @@ function createMapStateToProps() {
|
||||
function createMapDispatchToProps(dispatch, props) {
|
||||
return {
|
||||
onRemovePress() {
|
||||
dispatch(removeBlacklistItem({ id: props.id }));
|
||||
dispatch(removeBlocklistItem({ id: props.id }));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(BlacklistRow);
|
||||
export default connect(createMapStateToProps, createMapDispatchToProps)(BlocklistRow);
|
||||
@@ -282,6 +282,17 @@ class Queue extends Component {
|
||||
return !!(item && item.movieId);
|
||||
})
|
||||
)}
|
||||
allPending={isConfirmRemoveModalOpen && (
|
||||
selectedIds.every((id) => {
|
||||
const item = items.find((i) => i.id === id);
|
||||
|
||||
if (!item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.status === 'delay' || item.status === 'downloadClientUnavailable';
|
||||
})
|
||||
)}
|
||||
onRemovePress={this.onRemoveSelectedConfirmed}
|
||||
onModalClose={this.onConfirmRemoveModalClose}
|
||||
/>
|
||||
|
||||
@@ -42,14 +42,14 @@ class QueueRow extends Component {
|
||||
this.setState({ isRemoveQueueItemModalOpen: true });
|
||||
}
|
||||
|
||||
onRemoveQueueItemModalConfirmed = (blacklist) => {
|
||||
onRemoveQueueItemModalConfirmed = (blocklist) => {
|
||||
const {
|
||||
onRemoveQueueItemPress,
|
||||
onQueueRowModalOpenOrClose
|
||||
} = this.props;
|
||||
|
||||
onQueueRowModalOpenOrClose(false);
|
||||
onRemoveQueueItemPress(blacklist);
|
||||
onRemoveQueueItemPress(blocklist);
|
||||
|
||||
this.setState({ isRemoveQueueItemModalOpen: false });
|
||||
}
|
||||
@@ -332,6 +332,7 @@ class QueueRow extends Component {
|
||||
isOpen={isRemoveQueueItemModalOpen}
|
||||
sourceTitle={title}
|
||||
canIgnore={!!movie}
|
||||
isPending={isPending}
|
||||
onRemovePress={this.onRemoveQueueItemModalConfirmed}
|
||||
onModalClose={this.onRemoveQueueItemModalClose}
|
||||
/>
|
||||
|
||||
@@ -22,7 +22,7 @@ class RemoveQueueItemModal extends Component {
|
||||
|
||||
this.state = {
|
||||
remove: true,
|
||||
blacklist: false
|
||||
blocklist: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -32,7 +32,7 @@ class RemoveQueueItemModal extends Component {
|
||||
resetState = function() {
|
||||
this.setState({
|
||||
remove: true,
|
||||
blacklist: false
|
||||
blocklist: false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,8 +43,8 @@ class RemoveQueueItemModal extends Component {
|
||||
this.setState({ remove: value });
|
||||
}
|
||||
|
||||
onBlacklistChange = ({ value }) => {
|
||||
this.setState({ blacklist: value });
|
||||
onBlocklistChange = ({ value }) => {
|
||||
this.setState({ blocklist: value });
|
||||
}
|
||||
|
||||
onRemoveConfirmed = () => {
|
||||
@@ -66,10 +66,11 @@ class RemoveQueueItemModal extends Component {
|
||||
const {
|
||||
isOpen,
|
||||
sourceTitle,
|
||||
canIgnore
|
||||
canIgnore,
|
||||
isPending
|
||||
} = this.props;
|
||||
|
||||
const { remove, blacklist } = this.state;
|
||||
const { remove, blocklist } = this.state;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -89,27 +90,31 @@ class RemoveQueueItemModal extends Component {
|
||||
{translate('RemoveFromQueueText', [sourceTitle])}
|
||||
</div>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||
{
|
||||
isPending ?
|
||||
null :
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('BlacklistRelease')}</FormLabel>
|
||||
<FormLabel>{translate('BlocklistRelease')}</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="blacklist"
|
||||
value={blacklist}
|
||||
helpText={translate('BlacklistHelpText')}
|
||||
onChange={this.onBlacklistChange}
|
||||
name="blocklist"
|
||||
value={blocklist}
|
||||
helpText={translate('BlocklistHelpText')}
|
||||
onChange={this.onBlocklistChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -137,6 +142,7 @@ RemoveQueueItemModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
sourceTitle: PropTypes.string.isRequired,
|
||||
canIgnore: PropTypes.bool.isRequired,
|
||||
isPending: PropTypes.bool.isRequired,
|
||||
onRemovePress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ class RemoveQueueItemsModal extends Component {
|
||||
|
||||
this.state = {
|
||||
remove: true,
|
||||
blacklist: false
|
||||
blocklist: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ class RemoveQueueItemsModal extends Component {
|
||||
resetState = function() {
|
||||
this.setState({
|
||||
remove: true,
|
||||
blacklist: false
|
||||
blocklist: false
|
||||
});
|
||||
}
|
||||
|
||||
@@ -44,8 +44,8 @@ class RemoveQueueItemsModal extends Component {
|
||||
this.setState({ remove: value });
|
||||
}
|
||||
|
||||
onBlacklistChange = ({ value }) => {
|
||||
this.setState({ blacklist: value });
|
||||
onBlocklistChange = ({ value }) => {
|
||||
this.setState({ blocklist: value });
|
||||
}
|
||||
|
||||
onRemoveConfirmed = () => {
|
||||
@@ -67,10 +67,11 @@ class RemoveQueueItemsModal extends Component {
|
||||
const {
|
||||
isOpen,
|
||||
selectedCount,
|
||||
canIgnore
|
||||
canIgnore,
|
||||
allPending
|
||||
} = this.props;
|
||||
|
||||
const { remove, blacklist } = this.state;
|
||||
const { remove, blocklist } = this.state;
|
||||
|
||||
return (
|
||||
<Modal
|
||||
@@ -82,38 +83,42 @@ class RemoveQueueItemsModal extends Component {
|
||||
onModalClose={this.onModalClose}
|
||||
>
|
||||
<ModalHeader>
|
||||
Remove Selected Item{selectedCount > 1 ? 's' : ''}
|
||||
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
|
||||
</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<div className={styles.message}>
|
||||
{translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', [selectedCount, selectedCount > 1 ? 's' : ''])}
|
||||
{selectedCount > 1 ? translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', selectedCount) : translate('AreYouSureYouWantToRemoveSelectedItemFromQueue')}
|
||||
</div>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||
{
|
||||
allPending ?
|
||||
null :
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="remove"
|
||||
value={remove}
|
||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||
isDisabled={!canIgnore}
|
||||
onChange={this.onRemoveChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
}
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>
|
||||
Blacklist Release{selectedCount > 1 ? 's' : ''}
|
||||
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
|
||||
</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.CHECK}
|
||||
name="blacklist"
|
||||
value={blacklist}
|
||||
helpText={translate('BlacklistHelpText')}
|
||||
onChange={this.onBlacklistChange}
|
||||
name="blocklist"
|
||||
value={blocklist}
|
||||
helpText={translate('BlocklistHelpText')}
|
||||
onChange={this.onBlocklistChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
@@ -141,6 +146,7 @@ RemoveQueueItemsModal.propTypes = {
|
||||
isOpen: PropTypes.bool.isRequired,
|
||||
selectedCount: PropTypes.number.isRequired,
|
||||
canIgnore: PropTypes.bool.isRequired,
|
||||
allPending: PropTypes.bool.isRequired,
|
||||
onRemovePress: PropTypes.func.isRequired,
|
||||
onModalClose: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -103,7 +103,7 @@ class AddNewMovie extends Component {
|
||||
className={styles.searchInput}
|
||||
name="movieLookup"
|
||||
value={term}
|
||||
placeholder="eg. The Dark Knight, tmdb:155, imdb:tt0468569"
|
||||
placeholder="e.g. The Dark Knight, tmdb:155, imdb:tt0468569"
|
||||
autoFocus={true}
|
||||
onChange={this.onSearchInputChange}
|
||||
/>
|
||||
@@ -161,7 +161,7 @@ class AddNewMovie extends Component {
|
||||
{translate('YouCanAlsoSearch')}
|
||||
</div>
|
||||
<div>
|
||||
<Link to="https://wiki.servarr.com/Radarr_FAQ#Why_cant_I_add_a_new_movie_to_Radarr">
|
||||
<Link to="https://wiki.servarr.com/radarr/faq#why-cant-i-add-a-new-movie-to-radarr">
|
||||
{translate('CantFindMovie')}
|
||||
</Link>
|
||||
</div>
|
||||
|
||||
@@ -30,3 +30,9 @@
|
||||
.importButtonIcon {
|
||||
margin-right: 8px;
|
||||
}
|
||||
|
||||
.addErrorAlert {
|
||||
composes: alert from '~Components/Alert.css';
|
||||
|
||||
margin: 20px 0;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import FieldSet from 'Components/FieldSet';
|
||||
import FileBrowserModal from 'Components/FileBrowser/FileBrowserModal';
|
||||
import Icon from 'Components/Icon';
|
||||
@@ -72,23 +73,29 @@ class ImportMovieSelectFolder extends Component {
|
||||
isWindows,
|
||||
isFetching,
|
||||
isPopulated,
|
||||
isSaving,
|
||||
error,
|
||||
saveError,
|
||||
items
|
||||
} = this.props;
|
||||
|
||||
const hasRootFolders = items.length > 0;
|
||||
|
||||
return (
|
||||
<PageContent title={translate('ImportMovies')}>
|
||||
<PageContentBody>
|
||||
{
|
||||
isFetching && !isPopulated &&
|
||||
<LoadingIndicator />
|
||||
isFetching && !isPopulated ?
|
||||
<LoadingIndicator /> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
!isFetching && error ?
|
||||
<div>
|
||||
{translate('UnableToLoadRootFolders')}
|
||||
</div>
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
@@ -108,7 +115,7 @@ class ImportMovieSelectFolder extends Component {
|
||||
</div>
|
||||
|
||||
{
|
||||
items.length > 0 ?
|
||||
hasRootFolders ?
|
||||
<div className={styles.recentFolders}>
|
||||
<FieldSet legend={translate('RecentFolders')}>
|
||||
<Table
|
||||
@@ -131,35 +138,51 @@ class ImportMovieSelectFolder extends Component {
|
||||
</TableBody>
|
||||
</Table>
|
||||
</FieldSet>
|
||||
|
||||
<Button
|
||||
kind={kinds.PRIMARY}
|
||||
size={sizes.LARGE}
|
||||
onPress={this.onAddNewRootFolderPress}
|
||||
>
|
||||
<Icon
|
||||
className={styles.importButtonIcon}
|
||||
name={icons.DRIVE}
|
||||
/>
|
||||
{translate('ChooseAnotherFolder')}
|
||||
</Button>
|
||||
</div> :
|
||||
|
||||
<div className={styles.startImport}>
|
||||
<Button
|
||||
kind={kinds.PRIMARY}
|
||||
size={sizes.LARGE}
|
||||
onPress={this.onAddNewRootFolderPress}
|
||||
>
|
||||
<Icon
|
||||
className={styles.importButtonIcon}
|
||||
name={icons.DRIVE}
|
||||
/>
|
||||
{translate('StartImport')}
|
||||
</Button>
|
||||
</div>
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!isSaving && saveError ?
|
||||
<Alert
|
||||
className={styles.addErrorAlert}
|
||||
kind={kinds.DANGER}
|
||||
>
|
||||
{translate('UnableToAddRootFolder')}
|
||||
|
||||
<ul>
|
||||
{
|
||||
saveError.responseJSON.map((e, index) => {
|
||||
return (
|
||||
<li key={index}>
|
||||
{e.errorMessage}
|
||||
</li>
|
||||
);
|
||||
})
|
||||
}
|
||||
</ul>
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
<div className={hasRootFolders ? undefined : styles.startImport}>
|
||||
<Button
|
||||
kind={kinds.PRIMARY}
|
||||
size={sizes.LARGE}
|
||||
onPress={this.onAddNewRootFolderPress}
|
||||
>
|
||||
<Icon
|
||||
className={styles.importButtonIcon}
|
||||
name={icons.DRIVE}
|
||||
/>
|
||||
{
|
||||
hasRootFolders ?
|
||||
translate('ChooseAnotherFolder') :
|
||||
translate('StartImport')
|
||||
}
|
||||
</Button>
|
||||
</div>
|
||||
|
||||
<FileBrowserModal
|
||||
isOpen={this.state.isAddNewRootFolderModalOpen}
|
||||
name="rootFolderPath"
|
||||
@@ -179,7 +202,9 @@ ImportMovieSelectFolder.propTypes = {
|
||||
isWindows: PropTypes.bool.isRequired,
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
isPopulated: PropTypes.bool.isRequired,
|
||||
isSaving: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
saveError: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onNewRootFolderSelect: PropTypes.func.isRequired,
|
||||
onDeleteRootFolderPress: PropTypes.func.isRequired
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { Redirect, Route } from 'react-router-dom';
|
||||
import BlacklistConnector from 'Activity/Blacklist/BlacklistConnector';
|
||||
import BlocklistConnector from 'Activity/Blocklist/BlocklistConnector';
|
||||
import HistoryConnector from 'Activity/History/HistoryConnector';
|
||||
import QueueConnector from 'Activity/Queue/QueueConnector';
|
||||
import AddNewMovieConnector from 'AddMovie/AddNewMovie/AddNewMovieConnector';
|
||||
@@ -111,8 +111,8 @@ function AppRoutes(props) {
|
||||
/>
|
||||
|
||||
<Route
|
||||
path="/activity/blacklist"
|
||||
component={BlacklistConnector}
|
||||
path="/activity/blocklist"
|
||||
component={BlocklistConnector}
|
||||
/>
|
||||
|
||||
{/*
|
||||
|
||||
29
frontend/src/App/ThemeSelector.js
Normal file
29
frontend/src/App/ThemeSelector.js
Normal file
@@ -0,0 +1,29 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
|
||||
const theme = window.Radarr.theme;
|
||||
|
||||
function ThemeSelector({ children }) {
|
||||
return (
|
||||
<>
|
||||
{
|
||||
theme !== 'default' &&
|
||||
<>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href={'/Content/Theme.Park/radarr-base.css'}
|
||||
/>
|
||||
<link rel="stylesheet" type="text/css"
|
||||
href={`/Content/Theme.Park/Themes/${theme}.css`}
|
||||
/>
|
||||
</>
|
||||
}
|
||||
{children}
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
ThemeSelector.propTypes = {
|
||||
children: PropTypes.object.isRequired
|
||||
};
|
||||
|
||||
export default ThemeSelector;
|
||||
@@ -54,20 +54,24 @@
|
||||
composes: downloaded from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
.downloading {
|
||||
composes: downloading from '~Calendar/Events/CalendarEvent.css';
|
||||
.queue {
|
||||
composes: queue from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
.unmonitored {
|
||||
composes: unmonitored from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
.missing {
|
||||
composes: missing from '~Calendar/Events/CalendarEvent.css';
|
||||
.missingUnmonitored {
|
||||
composes: missingUnmonitored from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
.unreleased {
|
||||
composes: unreleased from '~Calendar/Events/CalendarEvent.css';
|
||||
.missingMonitored {
|
||||
composes: missingMonitored from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
.continuing {
|
||||
composes: continuing from '~Calendar/Events/CalendarEvent.css';
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointSmall) {
|
||||
|
||||
@@ -3,10 +3,10 @@ import moment from 'moment';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import CalendarEventQueueDetails from 'Calendar/Events/CalendarEventQueueDetails';
|
||||
import getStatusStyle from 'Calendar/getStatusStyle';
|
||||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './AgendaEvent.css';
|
||||
|
||||
@@ -82,7 +82,7 @@ class AgendaEvent extends Component {
|
||||
startTime = moment(startTime);
|
||||
const downloading = !!(queueItem || grabbed);
|
||||
const isMonitored = monitored;
|
||||
const statusStyle = getStatusStyle(hasFile, downloading, isAvailable, isMonitored);
|
||||
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', downloading);
|
||||
const joinedGenres = genres.slice(0, 2).join(', ');
|
||||
const link = `/movie/${titleSlug}`;
|
||||
|
||||
|
||||
@@ -60,39 +60,30 @@
|
||||
}
|
||||
}
|
||||
|
||||
.downloading {
|
||||
.queue {
|
||||
border-left-color: $purple !important;
|
||||
}
|
||||
|
||||
.unmonitored {
|
||||
border-left-color: $gray !important;
|
||||
}
|
||||
|
||||
.missingUnmonitored {
|
||||
border-left-color: $warningColor !important;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.onAir {
|
||||
border-left-color: $warningColor !important;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.missing {
|
||||
.missingMonitored {
|
||||
border-left-color: $dangerColor !important;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
border-left-color: color($dangerColor saturation(+15%)) !important;
|
||||
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.unreleased {
|
||||
.continuing {
|
||||
border-left-color: $primaryColor !important;
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,10 +2,10 @@ import classNames from 'classnames';
|
||||
import moment from 'moment';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import getStatusStyle from 'Calendar/getStatusStyle';
|
||||
import Icon from 'Components/Icon';
|
||||
import Link from 'Components/Link/Link';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
|
||||
import styles from './CalendarEvent.css';
|
||||
@@ -38,7 +38,7 @@ class CalendarEvent extends Component {
|
||||
|
||||
const isDownloading = !!(queueItem || grabbed);
|
||||
const isMonitored = monitored;
|
||||
const statusStyle = getStatusStyle(hasFile, isDownloading, isAvailable, isMonitored);
|
||||
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', isDownloading);
|
||||
const joinedGenres = genres.slice(0, 2).join(', ');
|
||||
const link = `/movie/${titleSlug}`;
|
||||
const eventType = [];
|
||||
|
||||
@@ -1,23 +0,0 @@
|
||||
|
||||
function getStatusStyle(hasFile, downloading, isAvailable, isMonitored) {
|
||||
|
||||
if (hasFile) {
|
||||
return 'downloaded';
|
||||
}
|
||||
|
||||
if (downloading) {
|
||||
return 'downloading';
|
||||
}
|
||||
|
||||
if (!isMonitored) {
|
||||
return 'unmonitored';
|
||||
}
|
||||
|
||||
if (isAvailable && !hasFile) {
|
||||
return 'missing';
|
||||
}
|
||||
|
||||
return 'unreleased';
|
||||
}
|
||||
|
||||
export default getStatusStyle;
|
||||
@@ -1,7 +1,7 @@
|
||||
export const APPLICATION_UPDATE = 'ApplicationUpdate';
|
||||
export const BACKUP = 'Backup';
|
||||
export const REFRESH_MONITORED_DOWNLOADS = 'RefreshMonitoredDownloads';
|
||||
export const CLEAR_BLACKLIST = 'ClearBlacklist';
|
||||
export const CLEAR_BLOCKLIST = 'ClearBlocklist';
|
||||
export const CLEAR_LOGS = 'ClearLog';
|
||||
export const CUTOFF_UNMET_MOVIES_SEARCH = 'CutoffUnmetMoviesSearch';
|
||||
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
||||
|
||||
@@ -129,7 +129,7 @@ class FileBrowserModalContent extends Component {
|
||||
className={styles.mappedDrivesWarning}
|
||||
kind={kinds.WARNING}
|
||||
>
|
||||
<Link to="https://wiki.servarr.com/Radarr_FAQ#Why_cant_Radarr_see_my_files_on_a_remote_server">
|
||||
<Link to="https://wiki.servarr.com/radarr/faq#why-cant-radarr-see-my-files-on-a-remote-server">
|
||||
{translate('MappedDrivesRunningAsService')}
|
||||
</Link> .
|
||||
</Alert>
|
||||
|
||||
@@ -113,6 +113,8 @@ function FormInputGroup(props) {
|
||||
helpTexts,
|
||||
helpTextWarning,
|
||||
helpLink,
|
||||
inlineLink,
|
||||
tooltip,
|
||||
pending,
|
||||
errors,
|
||||
warnings,
|
||||
@@ -182,6 +184,9 @@ function FormInputGroup(props) {
|
||||
!checkInput && helpText &&
|
||||
<FormInputHelpText
|
||||
text={helpText}
|
||||
link={inlineLink}
|
||||
tooltip={tooltip}
|
||||
isWarning={!!inlineLink}
|
||||
/>
|
||||
}
|
||||
|
||||
@@ -263,6 +268,8 @@ FormInputGroup.propTypes = {
|
||||
helpTexts: PropTypes.arrayOf(PropTypes.string),
|
||||
helpTextWarning: PropTypes.string,
|
||||
helpLink: PropTypes.string,
|
||||
inlineLink: PropTypes.string,
|
||||
tooltip: PropTypes.string,
|
||||
pending: PropTypes.bool,
|
||||
errors: PropTypes.arrayOf(PropTypes.object),
|
||||
warnings: PropTypes.arrayOf(PropTypes.object)
|
||||
|
||||
@@ -61,8 +61,8 @@ const links = [
|
||||
to: '/activity/history'
|
||||
},
|
||||
{
|
||||
title: translate('Blacklist'),
|
||||
to: '/activity/blacklist'
|
||||
title: translate('Blocklist'),
|
||||
to: '/activity/blocklist'
|
||||
}
|
||||
]
|
||||
},
|
||||
|
||||
@@ -49,7 +49,7 @@
|
||||
background-color: $dangerColor;
|
||||
|
||||
&: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, $dangerColor, $dangerColor 5px, $dangerColor 5px, $dimColor 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
background-color: $warningColor;
|
||||
|
||||
&: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, $warningColor, $warningColor 5px, $warningColor 5px, $dimColor 10px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BIN
frontend/src/Content/Images/Icons/logo-prowlarr.png
Normal file
BIN
frontend/src/Content/Images/Icons/logo-prowlarr.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.4 KiB |
BIN
frontend/src/Content/Theme.Park/Resources/blur-noise.png
Normal file
BIN
frontend/src/Content/Theme.Park/Resources/blur-noise.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 92 KiB |
30
frontend/src/Content/Theme.Park/Themes/aquamarine.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/aquamarine.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(ellipse at center, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: radial-gradient(ellipse at top, #47918a 0%, #0b3161 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #009688;
|
||||
--button-color-hover: #12afa0;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 18, 175, 160;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #0ed2bf;
|
||||
--link-color-hover: #36e7d6;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #009688; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: rgb(21, 213, 194);
|
||||
--petio-spinner: invert(39%) sepia(98%) saturate(527%) hue-rotate(129deg) brightness(94%) contrast(101%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 18, 175, 160;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/dark.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/dark.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(circle, #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(circle , #3a3a3a, #2d2d2d, #202020, #141414, #000000) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: #2d2d2d;
|
||||
|
||||
--button-color: #7a7a7a;
|
||||
--button-color-hover: #9b9b9b;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 170, 170, 170;
|
||||
--accent-color-hover: rgba(255, 255, 255, 0.45);
|
||||
--link-color: #7a7a7a;
|
||||
--link-color-hover: #fff;
|
||||
--label-text-color: black;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #6b5; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #e5a00d;
|
||||
--petio-spinner: invert(35%) sepia(12%) saturate(4%) hue-rotate(2deg) brightness(104%) contrast(86%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 255, 255, 255;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/dracula.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/dracula.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #282a36;
|
||||
|
||||
--modal-bg-color: #1e2029;
|
||||
--modal-header-color: #1e2029;
|
||||
--modal-footer-color: #1e2029;
|
||||
|
||||
--drop-down-menu-bg: #1e2029;
|
||||
|
||||
--button-color: #bd93f9;
|
||||
--button-color-hover: #ff79c6;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 80, 250, 123;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #ff79c6;
|
||||
--link-color-hover: #8be9fd;
|
||||
--label-text-color: #282a36;
|
||||
|
||||
--text:#6272a4;
|
||||
--text-hover: #95adfa;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #50fa7b; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #bd93f9;
|
||||
--petio-spinner: invert(79%) sepia(27%) saturate(1033%) hue-rotate(74deg) brightness(104%) contrast(96%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 80, 250, 123;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/hotline.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/hotline.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: linear-gradient(0deg, rgba(247,101,184,1) 0%, rgb(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: linear-gradient(90deg, rgba(247,101,184,1) 0%, rgba(21, 95, 165) 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #f98dc9;
|
||||
--button-color-hover: #ff4cb1;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 249, 141, 201;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color:rgb(255, 179, 222);
|
||||
--link-color-hover: #d7fffe;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #f98dc9; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #f765b8;
|
||||
--petio-spinner: invert(78%) sepia(17%) saturate(4447%) hue-rotate(290deg) brightness(109%) contrast(95%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 215,255,254;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/hotpink.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/hotpink.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(45deg, #fb3f62 0%, #204c80 37%, #004249 97%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(circle, #204c80 0%, #000 100%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: #204c80;
|
||||
|
||||
--button-color: #fb3f62;
|
||||
--button-color-hover: #cd4164;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #FFF;
|
||||
|
||||
--accent-color: 251, 63, 98;
|
||||
--accent-color-hover: rgba(var(--accent-color), .8);
|
||||
--link-color: rgb(0, 255, 157);
|
||||
--link-color-hover: rgba(0, 255, 157, 0.8);
|
||||
--label-text-color: #282a36;
|
||||
|
||||
--text:#eee;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
--arr-queue-color: rgb(0, 255, 157);
|
||||
--plex-poster-unwatched: #fb3f62;
|
||||
--petio-spinner: invert(29%) sepia(87%) saturate(2199%) hue-rotate(331deg) brightness(115%) contrast(97%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 251, 63, 98;
|
||||
}
|
||||
|
||||
30
frontend/src/Content/Theme.Park/Themes/nord.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/nord.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #2E3440;
|
||||
|
||||
--modal-bg-color: #3B4252;
|
||||
--modal-header-color: #434C5E;
|
||||
--modal-footer-color: #434C5E;
|
||||
|
||||
--drop-down-menu-bg: #3B4252;
|
||||
|
||||
--button-color: #79b8ca;
|
||||
--button-color-hover: #6a9daf;
|
||||
--button-text: #2E3440;
|
||||
--button-text-hover: #D8DEE9;
|
||||
|
||||
--accent-color: 121, 184, 202;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #81A1C1;
|
||||
--link-color-hover: #88C0D0;
|
||||
--label-text-color: #222730;
|
||||
|
||||
--text:#D8DEE9;
|
||||
--text-hover: #ECEFF4;
|
||||
--text-muted: #81A1C1;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #A3BE8C; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #D08770;
|
||||
--petio-spinner: invert(83%) sepia(9%) saturate(1787%) hue-rotate(156deg) brightness(85%) contrast(83%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 121, 184, 202;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/organizr.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/organizr.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: #1f1f1f;
|
||||
|
||||
--modal-bg-color: #333;
|
||||
--modal-header-color: #232323;
|
||||
--modal-footer-color: #232323;
|
||||
|
||||
--drop-down-menu-bg: #1b1b1b;
|
||||
|
||||
--button-color: #2cabe3;
|
||||
--button-color-hover: #298fbc;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 44, 171, 227;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #2cabe3;
|
||||
--link-color-hover: #3cc5ff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#96a2b4;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #2cabe3; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #2cabe3;
|
||||
--petio-spinner: invert(65%) sepia(83%) saturate(2026%) hue-rotate(167deg) brightness(90%) contrast(97%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 44, 171, 227;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/overseerr.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/overseerr.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: linear-gradient(360deg, hsl(221, 39%, 11%) 65%, hsl(215, 28%, 17%) 100%);
|
||||
|
||||
--modal-bg-color: #1f2937;
|
||||
--modal-header-color: #1f2937;
|
||||
--modal-footer-color: #1f2937;
|
||||
|
||||
--drop-down-menu-bg: #374151;
|
||||
|
||||
--button-color: #4f46e5;
|
||||
--button-color-hover: #6366f1;
|
||||
--button-text: #e5e7eb;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 167, 139, 250;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #6366f1;
|
||||
--link-color-hover: #a78bfa;
|
||||
--label-text-color: #000;
|
||||
|
||||
--text: #d1d5db;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #9ca3af;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #6366f1; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #6366f1;
|
||||
--petio-spinner: invert(24%) sepia(59%) saturate(3411%) hue-rotate(237deg) brightness(91%) contrast(96%); /* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 98, 116, 145;
|
||||
}
|
||||
28
frontend/src/Content/Theme.Park/Themes/plex.css
Normal file
28
frontend/src/Content/Theme.Park/Themes/plex.css
Normal file
@@ -0,0 +1,28 @@
|
||||
:root {
|
||||
--main-bg-color: url("Resources/blur-noise.png") repeat scroll 0% 0%, radial-gradient(circle at 0% 100%, rgba(54, 66, 84, 0.55) 0%, rgba(54, 66, 84, 0.043) 70%, rgba(54, 66, 84, 0) 80%), radial-gradient(circle at 100% 100%, rgba(113, 135, 153, 0.55) 0%, rgba(113, 135, 153, 0.043) 70%, rgba(113, 135, 153, 0) 80%), radial-gradient(circle at 100% 0%, rgba(54, 66, 84, 0.55) 0%, rgba(54, 66, 84, 0.043) 70%, rgba(54, 66, 84, 0) 80%), radial-gradient(circle at 0% 0%, rgba(91, 114, 135, 0.55) 0%, rgba(91, 114, 135, 0.043) 70%, rgba(91, 114, 135, 0) 80%), rgb(0, 0, 0) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: #1f2326;
|
||||
--modal-header-color: #1f2326;
|
||||
--modal-footer-color: #323232;
|
||||
|
||||
--drop-down-menu-bg: #191a1c;
|
||||
|
||||
--button-color: #cc7b19;
|
||||
--button-color-hover: #e59029;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 229, 160, 13;
|
||||
--accent-color-hover: #ffc107;
|
||||
--link-color: #e5a00d;
|
||||
--link-color-hover: #fff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#ddd;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
--arr-queue-color: #27c24c;
|
||||
--petio-spinner: invert(0%) sepia(0%) saturate(100%) hue-rotate(0deg) brightness(100%) contrast(100%);
|
||||
--gitea-color-primary-dark-4: 255, 193, 7;
|
||||
}
|
||||
124
frontend/src/Content/Theme.Park/Themes/radarr-darker.css
Normal file
124
frontend/src/Content/Theme.Park/Themes/radarr-darker.css
Normal file
@@ -0,0 +1,124 @@
|
||||
:root {
|
||||
--main-bg-color: #454545;
|
||||
|
||||
--modal-bg-color: #595959;
|
||||
--modal-header-color: #595959;
|
||||
--modal-footer-color: #595959;
|
||||
|
||||
--drop-down-menu-bg: #606060;
|
||||
|
||||
--button-color: #5899eb;
|
||||
--button-color-hover: #4b91ea;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 255, 194, 48;
|
||||
--accent-color-hover: rgb(255, 194, 48, .8);
|
||||
--link-color: rgb(255, 194, 48);
|
||||
--link-color-hover: rgb(255, 194, 48, .8);
|
||||
--label-text-color: #eee;
|
||||
|
||||
--text: #ccc;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #5d9cec;
|
||||
--side-menu-active: #333333;
|
||||
--scroller-hover: #606060;
|
||||
--scroller: #707070;
|
||||
--border-color: #606060;
|
||||
--label-color: #707070;
|
||||
--label-info: #5d9cec;
|
||||
--header-color: #464b51;
|
||||
--side-menu-color: #595959;
|
||||
}
|
||||
|
||||
/* HEADER */
|
||||
|
||||
[class*="PageHeader-header-"] {
|
||||
background-color: var(--header-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[class*="PageToolbar-toolbar-"] {
|
||||
background-color: #707070;
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* SIDE MENU */
|
||||
|
||||
[class*="PageSidebar-sidebar-"] {
|
||||
background-color: var(--side-menu-color);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-link-]:focus {
|
||||
color: rgb(var(--accent-color)) !important;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-isActiveLink-] {
|
||||
color: var(--link-color) !important;
|
||||
}
|
||||
|
||||
[class*=PageSidebarItem-isActiveParentLink-] {
|
||||
background-color: var(--side-menu-active);
|
||||
}
|
||||
|
||||
/* SCROLLER */
|
||||
[class*=ImportSeriesSelectSeries-results-]::-webkit-scrollbar-thumb:hover,
|
||||
[class*=OverlayScroller-thumb-]:hover {
|
||||
background-color: var(--scroller-hover) !important;
|
||||
}
|
||||
|
||||
[class*="OverlayScroller-thumb-"],
|
||||
[class*=Scroller-scroller-]::-webkit-scrollbar-thumb {
|
||||
background-color: var(--scroller) !important;
|
||||
}
|
||||
|
||||
/* MODALS */
|
||||
|
||||
[class*=ModalHeader-modalHeader-],
|
||||
[class*=FieldSet-legend-] {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
[class*=ModalFooter-modalFooter-] {
|
||||
border-top: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* LABLES */
|
||||
|
||||
[class*="Label-default-"] {
|
||||
border-color: var(--label-color);
|
||||
background-color: var(--label-color);
|
||||
color: white;
|
||||
}
|
||||
|
||||
[class*="Label-info-"]:not([class*="PageSidebarItem-status-"] [class*="Label-info-"]) {
|
||||
border-color: var(--label-info);
|
||||
background-color: var(--label-info);
|
||||
color: #fff;
|
||||
}
|
||||
|
||||
/* SETTINGS */
|
||||
|
||||
[class*=Settings-link-] {
|
||||
border-bottom: 1px solid var(--border-color);
|
||||
}
|
||||
|
||||
/* SEARCH DROP DOWN */
|
||||
|
||||
[class*="MovieSearchInput-containerOpen-"] [class*="MovieSearchInput-movieContainer-"] {
|
||||
border: 1px solid var(--drop-down-menu-bg);
|
||||
background-color: var(--drop-down-menu-bg);
|
||||
box-shadow: inset 0 1px 1px rgb(0 0 0 / 8%);
|
||||
color: #e1e2e3;
|
||||
}
|
||||
|
||||
/* SERIES PAGE */
|
||||
|
||||
[class*="MovieIndexPoster-controls-"] {
|
||||
background-color: var(--label-color) !important;
|
||||
color: #fff !important;
|
||||
}
|
||||
30
frontend/src/Content/Theme.Park/Themes/space-gray.css
Normal file
30
frontend/src/Content/Theme.Park/Themes/space-gray.css
Normal file
@@ -0,0 +1,30 @@
|
||||
:root {
|
||||
--main-bg-color: radial-gradient(ellipse at center, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--modal-bg-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
--modal-header-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
--modal-footer-color: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--drop-down-menu-bg: radial-gradient(ellipse at top, rgba(87, 108, 117, 1) 0%, rgba(37, 50, 55, 1) 100.2%) center center/cover no-repeat fixed;
|
||||
|
||||
--button-color: #607D8B;
|
||||
--button-color-hover: #81a6b7;
|
||||
--button-text: #eee;
|
||||
--button-text-hover: #fff;
|
||||
|
||||
--accent-color: 129, 166, 183;
|
||||
--accent-color-hover: rgb(var(--accent-color),.8);
|
||||
--link-color: #81a6b7;
|
||||
--link-color-hover: #9adfff;
|
||||
--label-text-color: #fff;
|
||||
|
||||
--text:#bbb;
|
||||
--text-hover: #fff;
|
||||
--text-muted: #999;
|
||||
|
||||
/*Specials*/
|
||||
--arr-queue-color: #81a6b7; /* Servarr apps + Bazarr*/
|
||||
--plex-poster-unwatched: #70aeca;
|
||||
--petio-spinner: invert(50%) sepia(31%) saturate(341%) hue-rotate(155deg) brightness(88%) contrast(85%);/* Made with https://codepen.io/jsm91/embed/ZEEawyZ */
|
||||
--gitea-color-primary-dark-4: 129, 166, 183;
|
||||
}
|
||||
1101
frontend/src/Content/Theme.Park/radarr-base.css
Normal file
1101
frontend/src/Content/Theme.Park/radarr-base.css
Normal file
File diff suppressed because it is too large
Load Diff
@@ -225,4 +225,4 @@ export const UNSAVED_SETTING = farDotCircle;
|
||||
export const VIEW = fasEye;
|
||||
export const WARNING = fasExclamationTriangle;
|
||||
export const WIKI = fasBookReader;
|
||||
export const BLACKLIST = fasBan;
|
||||
export const BLOCKLIST = fasBan;
|
||||
|
||||
@@ -64,6 +64,7 @@ const columns = [
|
||||
name: icons.DANGER,
|
||||
kind: kinds.DANGER
|
||||
}),
|
||||
isSortable: true,
|
||||
isVisible: true
|
||||
}
|
||||
];
|
||||
|
||||
@@ -67,6 +67,6 @@
|
||||
width: 75px;
|
||||
}
|
||||
|
||||
.blacklist {
|
||||
.blocklist {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
@@ -127,7 +127,7 @@ class InteractiveSearchRow extends Component {
|
||||
grabError,
|
||||
historyGrabbedData,
|
||||
historyFailedData,
|
||||
blacklistData
|
||||
blocklistData
|
||||
} = this.props;
|
||||
|
||||
return (
|
||||
@@ -221,12 +221,12 @@ class InteractiveSearchRow extends Component {
|
||||
}
|
||||
|
||||
{
|
||||
blacklistData?.date &&
|
||||
blocklistData?.date &&
|
||||
<Icon
|
||||
className={historyGrabbedData || historyFailedData ? styles.blacklist : ''}
|
||||
name={icons.BLACKLIST}
|
||||
className={historyGrabbedData || historyFailedData ? styles.blocklist : ''}
|
||||
name={icons.BLOCKLIST}
|
||||
kind={kinds.DANGER}
|
||||
title={`${translate('Blacklisted')}: ${formatDateTime(blacklistData.date, longDateFormat, timeFormat, { includeSeconds: true })}`}
|
||||
title={`${translate('Blocklisted')}: ${formatDateTime(blocklistData.date, longDateFormat, timeFormat, { includeSeconds: true })}`}
|
||||
/>
|
||||
}
|
||||
</TableRowCell>
|
||||
@@ -341,7 +341,7 @@ InteractiveSearchRow.propTypes = {
|
||||
onGrabPress: PropTypes.func.isRequired,
|
||||
historyFailedData: PropTypes.object,
|
||||
historyGrabbedData: PropTypes.object,
|
||||
blacklistData: PropTypes.object
|
||||
blocklistData: PropTypes.object
|
||||
};
|
||||
|
||||
InteractiveSearchRow.defaultProps = {
|
||||
|
||||
@@ -8,22 +8,22 @@ function createMapStateToProps() {
|
||||
return createSelector(
|
||||
(state, { guid }) => guid,
|
||||
(state) => state.movieHistory.items,
|
||||
(state) => state.movieBlacklist.items,
|
||||
(guid, movieHistory, movieBlacklist) => {
|
||||
(state) => state.movieBlocklist.items,
|
||||
(guid, movieHistory, movieBlocklist) => {
|
||||
|
||||
let blacklistData = {};
|
||||
let blocklistData = {};
|
||||
let historyFailedData = {};
|
||||
|
||||
const historyGrabbedData = movieHistory.find((movie) => movie.eventType === 'grabbed' && movie.data.guid === guid);
|
||||
if (historyGrabbedData) {
|
||||
historyFailedData = movieHistory.find((movie) => movie.eventType === 'downloadFailed' && movie.sourceTitle === historyGrabbedData.sourceTitle);
|
||||
blacklistData = movieBlacklist.find((item) => item.sourceTitle === historyGrabbedData.sourceTitle);
|
||||
blocklistData = movieBlocklist.find((item) => item.sourceTitle === historyGrabbedData.sourceTitle);
|
||||
}
|
||||
|
||||
return {
|
||||
historyGrabbedData,
|
||||
historyFailedData,
|
||||
blacklistData
|
||||
blocklistData
|
||||
};
|
||||
}
|
||||
);
|
||||
@@ -38,7 +38,7 @@ class InteractiveSearchRowConnector extends Component {
|
||||
const {
|
||||
historyGrabbedData,
|
||||
historyFailedData,
|
||||
blacklistData,
|
||||
blocklistData,
|
||||
...otherProps
|
||||
} = this.props;
|
||||
|
||||
@@ -46,7 +46,7 @@ class InteractiveSearchRowConnector extends Component {
|
||||
<InteractiveSearchRow
|
||||
historyGrabbedData={historyGrabbedData}
|
||||
historyFailedData={historyFailedData}
|
||||
blacklistData={blacklistData}
|
||||
blocklistData={blocklistData}
|
||||
{...otherProps}
|
||||
/>
|
||||
);
|
||||
@@ -56,7 +56,7 @@ class InteractiveSearchRowConnector extends Component {
|
||||
InteractiveSearchRowConnector.propTypes = {
|
||||
historyGrabbedData: PropTypes.object,
|
||||
historyFailedData: PropTypes.object,
|
||||
blacklistData: PropTypes.object
|
||||
blocklistData: PropTypes.object
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps)(InteractiveSearchRowConnector);
|
||||
|
||||
@@ -151,7 +151,8 @@
|
||||
.qualityProfileName,
|
||||
.statusName,
|
||||
.studio,
|
||||
.collection {
|
||||
.collection,
|
||||
.genres {
|
||||
font-weight: 300;
|
||||
font-size: 17px;
|
||||
}
|
||||
|
||||
@@ -266,6 +266,7 @@ class MovieDetails extends Component {
|
||||
qualityProfileId,
|
||||
monitored,
|
||||
studio,
|
||||
genres,
|
||||
collection,
|
||||
overview,
|
||||
youTubeTrailerId,
|
||||
@@ -582,6 +583,19 @@ class MovieDetails extends Component {
|
||||
</span>
|
||||
</InfoLabel>
|
||||
}
|
||||
|
||||
{
|
||||
!!genres.length && !isSmallScreen &&
|
||||
<InfoLabel
|
||||
className={styles.detailsInfoLabel}
|
||||
title={translate('Genres')}
|
||||
size={sizes.LARGE}
|
||||
>
|
||||
<span className={styles.genres}>
|
||||
{genres.join(', ')}
|
||||
</span>
|
||||
</InfoLabel>
|
||||
}
|
||||
</div>
|
||||
|
||||
<Measure onMeasure={this.onMeasure}>
|
||||
@@ -766,6 +780,7 @@ MovieDetails.propTypes = {
|
||||
monitored: PropTypes.bool.isRequired,
|
||||
status: PropTypes.string.isRequired,
|
||||
studio: PropTypes.string,
|
||||
genres: PropTypes.arrayOf(PropTypes.string).isRequired,
|
||||
collection: PropTypes.object,
|
||||
youTubeTrailerId: PropTypes.string,
|
||||
isAvailable: PropTypes.bool.isRequired,
|
||||
@@ -798,6 +813,7 @@ MovieDetails.propTypes = {
|
||||
};
|
||||
|
||||
MovieDetails.defaultProps = {
|
||||
genres: [],
|
||||
tags: [],
|
||||
isSaving: false,
|
||||
sizeOnDisk: 0
|
||||
|
||||
@@ -8,7 +8,7 @@ import * as commandNames from 'Commands/commandNames';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { clearExtraFiles, fetchExtraFiles } from 'Store/Actions/extraFileActions';
|
||||
import { toggleMovieMonitored } from 'Store/Actions/movieActions';
|
||||
import { clearMovieBlacklist, fetchMovieBlacklist } from 'Store/Actions/movieBlacklistActions';
|
||||
import { clearMovieBlocklist, fetchMovieBlocklist } from 'Store/Actions/movieBlocklistActions';
|
||||
import { clearMovieCredits, fetchMovieCredits } from 'Store/Actions/movieCreditsActions';
|
||||
import { clearMovieFiles, fetchMovieFiles } from 'Store/Actions/movieFileActions';
|
||||
import { clearMovieHistory, fetchMovieHistory } from 'Store/Actions/movieHistoryActions';
|
||||
@@ -222,11 +222,11 @@ function createMapDispatchToProps(dispatch, props) {
|
||||
onGoToMovie(titleSlug) {
|
||||
dispatch(push(`${window.Radarr.urlBase}/movie/${titleSlug}`));
|
||||
},
|
||||
dispatchFetchMovieBlacklist({ movieId }) {
|
||||
dispatch(fetchMovieBlacklist({ movieId }));
|
||||
dispatchFetchMovieBlocklist({ movieId }) {
|
||||
dispatch(fetchMovieBlocklist({ movieId }));
|
||||
},
|
||||
dispatchClearMovieBlacklist() {
|
||||
dispatch(clearMovieBlacklist());
|
||||
dispatchClearMovieBlocklist() {
|
||||
dispatch(clearMovieBlocklist());
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -280,7 +280,7 @@ class MovieDetailsConnector extends Component {
|
||||
const movieId = this.props.id;
|
||||
|
||||
this.props.dispatchFetchMovieFiles({ movieId });
|
||||
this.props.dispatchFetchMovieBlacklist({ movieId });
|
||||
this.props.dispatchFetchMovieBlocklist({ movieId });
|
||||
this.props.dispatchFetchMovieHistory({ movieId });
|
||||
this.props.dispatchFetchExtraFiles({ movieId });
|
||||
this.props.dispatchFetchMovieCredits({ movieId });
|
||||
@@ -290,7 +290,7 @@ class MovieDetailsConnector extends Component {
|
||||
|
||||
unpopulate = () => {
|
||||
this.props.dispatchCancelFetchReleases();
|
||||
this.props.dispatchClearMovieBlacklist();
|
||||
this.props.dispatchClearMovieBlocklist();
|
||||
this.props.dispatchClearMovieFiles();
|
||||
this.props.dispatchClearMovieHistory();
|
||||
this.props.dispatchClearExtraFiles();
|
||||
@@ -362,8 +362,8 @@ MovieDetailsConnector.propTypes = {
|
||||
dispatchClearQueueDetails: PropTypes.func.isRequired,
|
||||
dispatchFetchImportListSchema: PropTypes.func.isRequired,
|
||||
dispatchExecuteCommand: PropTypes.func.isRequired,
|
||||
dispatchFetchMovieBlacklist: PropTypes.func.isRequired,
|
||||
dispatchClearMovieBlacklist: PropTypes.func.isRequired,
|
||||
dispatchFetchMovieBlocklist: PropTypes.func.isRequired,
|
||||
dispatchClearMovieBlocklist: PropTypes.func.isRequired,
|
||||
onGoToMovie: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
background-color: $dangerColor;
|
||||
|
||||
&: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, $dangerColor, $dangerColor 5px, $dangerColor 5px, $dimColor 10px);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,7 +58,7 @@
|
||||
background-color: $warningColor;
|
||||
|
||||
&: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, $warningColor, $warningColor 5px, $warningColor 5px, $dimColor 10px);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,8 @@ import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import ProgressBar from 'Components/ProgressBar';
|
||||
import { sizes } from 'Helpers/Props';
|
||||
import getProgressBarKind from 'Utilities/Movie/getProgressBarKind';
|
||||
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
|
||||
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './MovieIndexProgressBar.css';
|
||||
|
||||
@@ -42,7 +42,7 @@ function MovieIndexProgressBar(props) {
|
||||
className={styles.progressBar}
|
||||
containerClassName={styles.progress}
|
||||
progress={progress}
|
||||
kind={getProgressBarKind(status, monitored, hasFile, isAvailable, queueStatusText)}
|
||||
kind={getStatusStyle(status, monitored, hasFile, isAvailable, 'kinds', queueStatusText)}
|
||||
size={detailedProgressBar ? sizes.MEDIUM : sizes.SMALL}
|
||||
showText={detailedProgressBar}
|
||||
width={posterWidth}
|
||||
|
||||
@@ -45,11 +45,16 @@
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
|
||||
.movieStatus,
|
||||
.movieStatus {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
|
||||
.certification {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 100px;
|
||||
flex: 0 0 90px;
|
||||
}
|
||||
|
||||
.year {
|
||||
|
||||
@@ -52,11 +52,16 @@
|
||||
flex: 0 0 100px;
|
||||
}
|
||||
|
||||
.movieStatus,
|
||||
.movieStatus {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
|
||||
.certification {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 100px;
|
||||
flex: 0 0 90px;
|
||||
}
|
||||
|
||||
.year {
|
||||
|
||||
@@ -2,3 +2,45 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.missingUnmonitoredBackground {
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.missingMonitoredBackground {
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.queue {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $queueColor;
|
||||
}
|
||||
|
||||
.continuing {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $primaryColor;
|
||||
}
|
||||
|
||||
.availNotMonitored {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $darkGray;
|
||||
}
|
||||
|
||||
.ended {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $successColor;
|
||||
}
|
||||
|
||||
.missingMonitored {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $dangerColor;
|
||||
}
|
||||
|
||||
.missingUnmonitored {
|
||||
padding-right: 2px;
|
||||
border-left: 5px solid $warningColor;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
import classNames from 'classnames';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Label from 'Components/Label';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import MovieQuality from 'Movie/MovieQuality';
|
||||
import getQueueStatusText from 'Utilities/Movie/getQueueStatusText';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './MovieFileStatus.css';
|
||||
@@ -13,7 +11,8 @@ function MovieFileStatus(props) {
|
||||
monitored,
|
||||
movieFile,
|
||||
queueStatus,
|
||||
queueState
|
||||
queueState,
|
||||
colorImpairedMode
|
||||
} = props;
|
||||
|
||||
const hasMovieFile = !!movieFile;
|
||||
@@ -24,12 +23,8 @@ function MovieFileStatus(props) {
|
||||
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<Label
|
||||
title={queueStatusText}
|
||||
kind={kinds.QUEUE}
|
||||
>
|
||||
{queueStatusText}
|
||||
</Label>
|
||||
<span className={styles.queue} />
|
||||
{queueStatusText}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -39,51 +34,44 @@ function MovieFileStatus(props) {
|
||||
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<MovieQuality
|
||||
title={quality.quality.name}
|
||||
size={movieFile.size}
|
||||
quality={quality}
|
||||
isMonitored={monitored}
|
||||
isCutoffNotMet={movieFile.qualityCutoffNotMet}
|
||||
/>
|
||||
<span className={styles.ended} />
|
||||
{quality.quality.name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (!monitored) {
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<Label
|
||||
title={translate('NotMonitored')}
|
||||
kind={kinds.WARNING}
|
||||
>
|
||||
{translate('NotMonitored')}
|
||||
</Label>
|
||||
<div className={classNames(
|
||||
styles.center,
|
||||
styles.missingUnmonitoredBackground,
|
||||
colorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
>
|
||||
<span className={styles.missingUnmonitored} />
|
||||
{translate('NotMonitored')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (hasReleased) {
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<Label
|
||||
title={translate('MovieAvailableButMissing')}
|
||||
kind={kinds.DANGER}
|
||||
>
|
||||
{translate('Missing')}
|
||||
</Label>
|
||||
<div className={classNames(
|
||||
styles.center,
|
||||
styles.missingMonitoredBackground,
|
||||
colorImpairedMode && 'colorImpaired'
|
||||
)}
|
||||
>
|
||||
<span className={styles.missingMonitored} />
|
||||
{translate('Missing')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.center}>
|
||||
<Label
|
||||
title={translate('NotAvailable')}
|
||||
kind={kinds.INFO}
|
||||
>
|
||||
{translate('NotAvailable')}
|
||||
</Label>
|
||||
<span className={styles.continuing} />
|
||||
{translate('NotAvailable')}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -93,7 +81,8 @@ MovieFileStatus.propTypes = {
|
||||
monitored: PropTypes.bool.isRequired,
|
||||
movieFile: PropTypes.object,
|
||||
queueStatus: PropTypes.string,
|
||||
queueState: PropTypes.string
|
||||
queueState: PropTypes.string,
|
||||
colorImpairedMode: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
export default MovieFileStatus;
|
||||
|
||||
@@ -3,18 +3,21 @@ import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import MovieFileStatus from './MovieFileStatus';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createMovieSelector(),
|
||||
(movie) => {
|
||||
createUISettingsSelector(),
|
||||
(movie, uiSettings) => {
|
||||
return {
|
||||
inCinemas: movie.inCinemas,
|
||||
isAvailable: movie.isAvailable,
|
||||
monitored: movie.monitored,
|
||||
grabbed: movie.grabbed,
|
||||
movieFile: movie.movieFile
|
||||
movieFile: movie.movieFile,
|
||||
colorImpairedMode: uiSettings.enableColorImpairedMode
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
@@ -33,3 +33,9 @@
|
||||
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.releaseGroup {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
width: 120px;
|
||||
}
|
||||
|
||||
@@ -74,6 +74,7 @@ class MovieFileEditorRow extends Component {
|
||||
mediaInfo,
|
||||
relativePath,
|
||||
size,
|
||||
releaseGroup,
|
||||
quality,
|
||||
qualityCutoffNotMet,
|
||||
customFormats,
|
||||
@@ -155,6 +156,12 @@ class MovieFileEditorRow extends Component {
|
||||
}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell
|
||||
className={styles.releaseGroup}
|
||||
>
|
||||
{releaseGroup}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell
|
||||
className={styles.formats}
|
||||
>
|
||||
@@ -216,6 +223,7 @@ MovieFileEditorRow.propTypes = {
|
||||
size: PropTypes.number.isRequired,
|
||||
relativePath: PropTypes.string.isRequired,
|
||||
quality: PropTypes.object.isRequired,
|
||||
releaseGroup: PropTypes.string,
|
||||
customFormats: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
qualityCutoffNotMet: PropTypes.bool.isRequired,
|
||||
languages: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
|
||||
@@ -39,6 +39,11 @@ const columns = [
|
||||
label: translate('Quality'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'releaseGroup',
|
||||
label: translate('ReleaseGroup'),
|
||||
isVisible: true
|
||||
},
|
||||
{
|
||||
name: 'quality.customFormats',
|
||||
label: translate('Formats'),
|
||||
|
||||
@@ -6,10 +6,10 @@ import { fetchCustomFormatSpecifications } from 'Store/Actions/settingsActions';
|
||||
import createProviderSettingsSelector from 'Store/Selectors/createProviderSettingsSelector';
|
||||
import ExportCustomFormatModalContent from './ExportCustomFormatModalContent';
|
||||
|
||||
const blacklistedProperties = ['id', 'implementationName', 'infoLink'];
|
||||
const omittedProperties = ['id', 'implementationName', 'infoLink'];
|
||||
|
||||
function replacer(key, value) {
|
||||
if (blacklistedProperties.includes(key)) {
|
||||
if (omittedProperties.includes(key)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
|
||||
@@ -57,7 +57,7 @@ class AddSpecificationModalContent extends Component {
|
||||
</div>
|
||||
<div>
|
||||
{translate('VisitGithubCustomFormatsAphrodite')}
|
||||
<Link to="https://wiki.servarr.com/Radarr_Settings#Custom_Formats_2">{translate('Wiki')}</Link>
|
||||
<Link to="https://wiki.servarr.com/radarr/settings#custom-formats-2">{translate('Wiki')}</Link>
|
||||
</div>
|
||||
</Alert>
|
||||
|
||||
|
||||
@@ -24,10 +24,7 @@ const requiresRestartKeys = [
|
||||
'enableSsl',
|
||||
'sslPort',
|
||||
'sslCertPath',
|
||||
'sslCertPassword',
|
||||
'authenticationMethod',
|
||||
'username',
|
||||
'password'
|
||||
'sslCertPassword'
|
||||
];
|
||||
|
||||
class GeneralSettings extends Component {
|
||||
|
||||
@@ -53,6 +53,7 @@ function HostSettings(props) {
|
||||
name="port"
|
||||
min={1}
|
||||
max={65535}
|
||||
autocomplete="off"
|
||||
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...port}
|
||||
|
||||
@@ -86,7 +86,6 @@ class SecuritySettings extends Component {
|
||||
name="authenticationMethod"
|
||||
values={authenticationMethodOptions}
|
||||
helpText={translate('AuthenticationMethodHelpText')}
|
||||
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...authenticationMethod}
|
||||
/>
|
||||
@@ -100,7 +99,6 @@ class SecuritySettings extends Component {
|
||||
<FormInputGroup
|
||||
type={inputTypes.TEXT}
|
||||
name="username"
|
||||
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...username}
|
||||
/>
|
||||
@@ -115,7 +113,6 @@ class SecuritySettings extends Component {
|
||||
<FormInputGroup
|
||||
type={inputTypes.PASSWORD}
|
||||
name="password"
|
||||
helpTextWarning={translate('RestartRequiredHelpTextWarning')}
|
||||
onChange={onInputChange}
|
||||
{...password}
|
||||
/>
|
||||
|
||||
@@ -55,7 +55,7 @@ function UpdateSettings(props) {
|
||||
type={inputTypes.TEXT}
|
||||
name="branch"
|
||||
helpText={usingExternalUpdateMechanism ? translate('BranchUpdateMechanism') : translate('BranchUpdate')}
|
||||
helpLink="https://wiki.servarr.com/Radarr_Settings#Updates"
|
||||
helpLink="https://wiki.servarr.com/radarr/settings#updates"
|
||||
{...branch}
|
||||
onChange={onInputChange}
|
||||
readOnly={usingExternalUpdateMechanism}
|
||||
@@ -92,7 +92,7 @@ function UpdateSettings(props) {
|
||||
name="updateMechanism"
|
||||
values={updateOptions}
|
||||
helpText={translate('UpdateMechanismHelpText')}
|
||||
helpLink="https://wiki.servarr.com/Radarr_Settings#Updates"
|
||||
helpLink="https://wiki.servarr.com/radarr/settings#updates"
|
||||
onChange={onInputChange}
|
||||
{...updateMechanism}
|
||||
/>
|
||||
|
||||
@@ -43,6 +43,7 @@ function EditIndexerModalContent(props) {
|
||||
enableInteractiveSearch,
|
||||
supportsRss,
|
||||
supportsSearch,
|
||||
tags,
|
||||
fields,
|
||||
priority
|
||||
} = item;
|
||||
@@ -135,6 +136,7 @@ function EditIndexerModalContent(props) {
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
<FormGroup
|
||||
advancedSettings={advancedSettings}
|
||||
isAdvanced={true}
|
||||
@@ -151,6 +153,18 @@ function EditIndexerModalContent(props) {
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>Tags</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.TAG}
|
||||
name="tags"
|
||||
helpText={translate('IndexerTagHelpText')}
|
||||
{...tags}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</Form>
|
||||
}
|
||||
</ModalBody>
|
||||
|
||||
@@ -4,6 +4,7 @@ import Card from 'Components/Card';
|
||||
import Label from 'Components/Label';
|
||||
import IconButton from 'Components/Link/IconButton';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import TagList from 'Components/TagList';
|
||||
import { icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import EditIndexerModalConnector from './EditIndexerModalConnector';
|
||||
@@ -68,6 +69,8 @@ class Indexer extends Component {
|
||||
enableRss,
|
||||
enableAutomaticSearch,
|
||||
enableInteractiveSearch,
|
||||
tags,
|
||||
tagList,
|
||||
supportsRss,
|
||||
supportsSearch,
|
||||
priority,
|
||||
@@ -133,6 +136,11 @@ class Indexer extends Component {
|
||||
}
|
||||
</div>
|
||||
|
||||
<TagList
|
||||
tags={tags}
|
||||
tagList={tagList}
|
||||
/>
|
||||
|
||||
<EditIndexerModalConnector
|
||||
id={id}
|
||||
isOpen={this.state.isEditIndexerModalOpen}
|
||||
@@ -160,6 +168,8 @@ Indexer.propTypes = {
|
||||
enableRss: PropTypes.bool.isRequired,
|
||||
enableAutomaticSearch: PropTypes.bool.isRequired,
|
||||
enableInteractiveSearch: PropTypes.bool.isRequired,
|
||||
tags: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
supportsRss: PropTypes.bool.isRequired,
|
||||
supportsSearch: PropTypes.bool.isRequired,
|
||||
onCloneIndexerPress: PropTypes.func.isRequired,
|
||||
|
||||
@@ -54,6 +54,7 @@ class Indexers extends Component {
|
||||
render() {
|
||||
const {
|
||||
items,
|
||||
tagList,
|
||||
dispatchCloneIndexer,
|
||||
onConfirmDeleteIndexer,
|
||||
...otherProps
|
||||
@@ -79,6 +80,7 @@ class Indexers extends Component {
|
||||
<Indexer
|
||||
key={item.id}
|
||||
{...item}
|
||||
tagList={tagList}
|
||||
showPriority={showPriority}
|
||||
onCloneIndexerPress={this.onCloneIndexerPress}
|
||||
onConfirmDeleteIndexer={onConfirmDeleteIndexer}
|
||||
@@ -119,6 +121,7 @@ Indexers.propTypes = {
|
||||
isFetching: PropTypes.bool.isRequired,
|
||||
error: PropTypes.object,
|
||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
tagList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
dispatchCloneIndexer: PropTypes.func.isRequired,
|
||||
onConfirmDeleteIndexer: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -4,13 +4,20 @@ import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { cloneIndexer, deleteIndexer, fetchIndexers } from 'Store/Actions/settingsActions';
|
||||
import createSortedSectionSelector from 'Store/Selectors/createSortedSectionSelector';
|
||||
import createTagsSelector from 'Store/Selectors/createTagsSelector';
|
||||
import sortByName from 'Utilities/Array/sortByName';
|
||||
import Indexers from './Indexers';
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createSortedSectionSelector('settings.indexers', sortByName),
|
||||
(indexers) => indexers
|
||||
createTagsSelector(),
|
||||
(indexers, tagList) => {
|
||||
return {
|
||||
...indexers,
|
||||
tagList
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -118,7 +118,7 @@ function IndexerOptions(props) {
|
||||
unit="minutes"
|
||||
helpText={translate('HelpText')}
|
||||
helpTextWarning={translate('RSSSyncIntervalHelpTextWarning')}
|
||||
helpLink="https://wiki.servarr.com/Radarr_FAQ#How_does_Radarr_work"
|
||||
helpLink="https://wiki.servarr.com/radarr/faq#how-does-radarr-work"
|
||||
onChange={onInputChange}
|
||||
{...settings.rssSyncInterval}
|
||||
/>
|
||||
|
||||
@@ -115,10 +115,10 @@ class NamingModal extends Component {
|
||||
];
|
||||
|
||||
const movieTokens = [
|
||||
{ token: '{Movie Title}', example: 'Movie Title!' },
|
||||
{ token: '{Movie Title}', example: 'Movie\'s Title' },
|
||||
{ token: '{Movie Title:DE}', example: 'Filetitle' },
|
||||
{ token: '{Movie CleanTitle}', example: 'Movie Title' },
|
||||
{ token: '{Movie TitleThe}', example: 'Movie Title, The' },
|
||||
{ token: '{Movie CleanTitle}', example: 'Movies Title' },
|
||||
{ token: '{Movie TitleThe}', example: 'Movie\'s Title, The' },
|
||||
{ token: '{Movie OriginalTitle}', example: 'Τίτλος ταινίας' },
|
||||
{ token: '{Movie TitleFirstCharacter}', example: 'M' },
|
||||
{ token: '{Movie Collection}', example: 'The Movie Collection' },
|
||||
@@ -132,8 +132,8 @@ class NamingModal extends Component {
|
||||
];
|
||||
|
||||
const qualityTokens = [
|
||||
{ token: '{Quality Full}', example: 'HDTV 720p Proper' },
|
||||
{ token: '{Quality Title}', example: 'HDTV 720p' }
|
||||
{ token: '{Quality Full}', example: 'HDTV-720p Proper' },
|
||||
{ token: '{Quality Title}', example: 'HDTV-720p' }
|
||||
];
|
||||
|
||||
const mediaInfoTokens = [
|
||||
@@ -164,7 +164,7 @@ class NamingModal extends Component {
|
||||
|
||||
const originalTokens = [
|
||||
{ token: '{Original Title}', example: 'Movie.Title.HDTV.x264-EVOLVE' },
|
||||
{ token: '{Original Filename}', example: 'Movie.title.hdtv.x264-EVOLVE' }
|
||||
{ token: '{Original Filename}', example: 'movie title hdtv.x264-Evolve' }
|
||||
];
|
||||
|
||||
return (
|
||||
|
||||
@@ -20,7 +20,8 @@ export const certificationCountryOptions = [
|
||||
{ key: 'gb', value: 'Great Britain' },
|
||||
{ key: 'it', value: 'Italy' },
|
||||
{ key: 'es', value: 'Spain' },
|
||||
{ key: 'us', value: 'United States' }
|
||||
{ key: 'us', value: 'United States' },
|
||||
{ key: 'nz', value: 'New Zealand' }
|
||||
];
|
||||
|
||||
function MetadataOptions(props) {
|
||||
|
||||
@@ -39,8 +39,8 @@ function NotificationEventItems(props) {
|
||||
<FormLabel>{translate('NotificationTriggers')}</FormLabel>
|
||||
<div>
|
||||
<FormInputHelpText
|
||||
text={translate('NotifcationTriggersHelpText')}
|
||||
link="https://wiki.servarr.com/Radarr_Settings#Connections"
|
||||
text={translate('NotificationTriggersHelpText')}
|
||||
link="https://wiki.servarr.com/radarr/settings#connections"
|
||||
/>
|
||||
<div className={styles.events}>
|
||||
<div>
|
||||
|
||||
@@ -22,6 +22,7 @@ function TagDetailsModalContent(props) {
|
||||
notifications,
|
||||
restrictions,
|
||||
importLists,
|
||||
indexers,
|
||||
onModalClose,
|
||||
onDeleteTagPress
|
||||
} = props;
|
||||
@@ -41,7 +42,7 @@ function TagDetailsModalContent(props) {
|
||||
}
|
||||
|
||||
{
|
||||
!!movies.length &&
|
||||
movies.length ?
|
||||
<FieldSet legend={translate('Movies')}>
|
||||
{
|
||||
movies.map((item) => {
|
||||
@@ -52,11 +53,12 @@ function TagDetailsModalContent(props) {
|
||||
);
|
||||
})
|
||||
}
|
||||
</FieldSet>
|
||||
</FieldSet> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!!delayProfiles.length &&
|
||||
delayProfiles.length ?
|
||||
<FieldSet legend={translate('DelayProfile')}>
|
||||
{
|
||||
delayProfiles.map((item) => {
|
||||
@@ -81,11 +83,12 @@ function TagDetailsModalContent(props) {
|
||||
);
|
||||
})
|
||||
}
|
||||
</FieldSet>
|
||||
</FieldSet> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!!notifications.length &&
|
||||
notifications.length ?
|
||||
<FieldSet legend={translate('Connections')}>
|
||||
{
|
||||
notifications.map((item) => {
|
||||
@@ -96,11 +99,12 @@ function TagDetailsModalContent(props) {
|
||||
);
|
||||
})
|
||||
}
|
||||
</FieldSet>
|
||||
</FieldSet> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
!!restrictions.length &&
|
||||
restrictions.length ?
|
||||
<FieldSet legend={translate('Restrictions')}>
|
||||
{
|
||||
restrictions.map((item) => {
|
||||
@@ -142,7 +146,24 @@ function TagDetailsModalContent(props) {
|
||||
);
|
||||
})
|
||||
}
|
||||
</FieldSet>
|
||||
</FieldSet> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
indexers.length ?
|
||||
<FieldSet legend="Indexers">
|
||||
{
|
||||
indexers.map((item) => {
|
||||
return (
|
||||
<div key={item.id}>
|
||||
{item.name}
|
||||
</div>
|
||||
);
|
||||
})
|
||||
}
|
||||
</FieldSet> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
@@ -192,6 +213,7 @@ TagDetailsModalContent.propTypes = {
|
||||
notifications: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
restrictions: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
importLists: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
indexers: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
onModalClose: PropTypes.func.isRequired,
|
||||
onDeleteTagPress: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -69,6 +69,14 @@ function createMatchingImportListsSelector() {
|
||||
);
|
||||
}
|
||||
|
||||
function createMatchingIndexersSelector() {
|
||||
return createSelector(
|
||||
(state, { indexerIds }) => indexerIds,
|
||||
(state) => state.settings.indexers.items,
|
||||
findMatchingItems
|
||||
);
|
||||
}
|
||||
|
||||
function createMapStateToProps() {
|
||||
return createSelector(
|
||||
createMatchingMoviesSelector(),
|
||||
@@ -76,13 +84,15 @@ function createMapStateToProps() {
|
||||
createMatchingNotificationsSelector(),
|
||||
createMatchingRestrictionsSelector(),
|
||||
createMatchingImportListsSelector(),
|
||||
(movies, delayProfiles, notifications, restrictions, importLists) => {
|
||||
createMatchingIndexersSelector(),
|
||||
(movies, delayProfiles, notifications, restrictions, importLists, indexers) => {
|
||||
return {
|
||||
movies,
|
||||
delayProfiles,
|
||||
notifications,
|
||||
restrictions,
|
||||
importLists
|
||||
importLists,
|
||||
indexers
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
@@ -57,7 +57,8 @@ class Tag extends Component {
|
||||
notificationIds,
|
||||
restrictionIds,
|
||||
importListIds,
|
||||
movieIds
|
||||
movieIds,
|
||||
indexerIds
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
@@ -70,7 +71,8 @@ class Tag extends Component {
|
||||
notificationIds.length ||
|
||||
restrictionIds.length ||
|
||||
importListIds.length ||
|
||||
movieIds.length
|
||||
movieIds.length ||
|
||||
indexerIds.length
|
||||
);
|
||||
|
||||
return (
|
||||
@@ -120,6 +122,14 @@ class Tag extends Component {
|
||||
{importListIds.length} list{importListIds.length > 1 && 's'}
|
||||
</div>
|
||||
}
|
||||
|
||||
{
|
||||
indexerIds.length ?
|
||||
<div>
|
||||
{indexerIds.length} indexer{indexerIds.length > 1 && 's'}
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -138,6 +148,7 @@ class Tag extends Component {
|
||||
notificationIds={notificationIds}
|
||||
restrictionIds={restrictionIds}
|
||||
importListIds={importListIds}
|
||||
indexerIds={indexerIds}
|
||||
isOpen={isDetailsModalOpen}
|
||||
onModalClose={this.onDetailsModalClose}
|
||||
onDeleteTagPress={this.onDeleteTagPress}
|
||||
@@ -165,6 +176,7 @@ Tag.propTypes = {
|
||||
restrictionIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
importListIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
movieIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
indexerIds: PropTypes.arrayOf(PropTypes.number).isRequired,
|
||||
onConfirmDeleteTag: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -173,7 +185,8 @@ Tag.defaultProps = {
|
||||
notificationIds: [],
|
||||
restrictionIds: [],
|
||||
importListIds: [],
|
||||
movieIds: []
|
||||
movieIds: [],
|
||||
indexerIds: []
|
||||
};
|
||||
|
||||
export default Tag;
|
||||
|
||||
@@ -2,7 +2,7 @@ import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { fetchDelayProfiles, fetchImportLists, fetchNotifications, fetchRestrictions } from 'Store/Actions/settingsActions';
|
||||
import { fetchDelayProfiles, fetchImportLists, fetchIndexers, fetchNotifications, fetchRestrictions } from 'Store/Actions/settingsActions';
|
||||
import { fetchTagDetails } from 'Store/Actions/tagActions';
|
||||
import Tags from './Tags';
|
||||
|
||||
@@ -29,7 +29,8 @@ const mapDispatchToProps = {
|
||||
dispatchFetchDelayProfiles: fetchDelayProfiles,
|
||||
dispatchFetchNotifications: fetchNotifications,
|
||||
dispatchFetchRestrictions: fetchRestrictions,
|
||||
dispatchFetchImportLists: fetchImportLists
|
||||
dispatchFetchImportLists: fetchImportLists,
|
||||
dispatchFetchIndexers: fetchIndexers
|
||||
};
|
||||
|
||||
class MetadatasConnector extends Component {
|
||||
@@ -43,7 +44,8 @@ class MetadatasConnector extends Component {
|
||||
dispatchFetchDelayProfiles,
|
||||
dispatchFetchNotifications,
|
||||
dispatchFetchRestrictions,
|
||||
dispatchFetchImportLists
|
||||
dispatchFetchImportLists,
|
||||
dispatchFetchIndexers
|
||||
} = this.props;
|
||||
|
||||
dispatchFetchTagDetails();
|
||||
@@ -51,6 +53,7 @@ class MetadatasConnector extends Component {
|
||||
dispatchFetchNotifications();
|
||||
dispatchFetchRestrictions();
|
||||
dispatchFetchImportLists();
|
||||
dispatchFetchIndexers();
|
||||
}
|
||||
|
||||
//
|
||||
@@ -70,7 +73,8 @@ MetadatasConnector.propTypes = {
|
||||
dispatchFetchDelayProfiles: PropTypes.func.isRequired,
|
||||
dispatchFetchNotifications: PropTypes.func.isRequired,
|
||||
dispatchFetchRestrictions: PropTypes.func.isRequired,
|
||||
dispatchFetchImportLists: PropTypes.func.isRequired
|
||||
dispatchFetchImportLists: PropTypes.func.isRequired,
|
||||
dispatchFetchIndexers: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
export default connect(createMapStateToProps, mapDispatchToProps)(MetadatasConnector);
|
||||
|
||||
@@ -48,6 +48,21 @@ export const movieRuntimeFormatOptions = [
|
||||
{ key: 'minutes', value: '75 mins' }
|
||||
];
|
||||
|
||||
export const themeOptions = [
|
||||
{ key: 'default', value: 'Default' },
|
||||
{ key: 'aquamarine', value: 'Aquamarine' },
|
||||
{ key: 'dark', value: 'Dark' },
|
||||
{ key: 'dracula', value: 'Dracula' },
|
||||
{ key: 'hotline', value: 'Hotline' },
|
||||
{ key: 'hotpink', value: 'Hotpink' },
|
||||
{ key: 'nord', value: 'Nord' },
|
||||
{ key: 'organizr', value: 'Organizr' },
|
||||
{ key: 'overseerr', value: 'Overseerr' },
|
||||
{ key: 'plex', value: 'Plex' },
|
||||
{ key: 'radarr-darker', value: 'Radarr Darker' },
|
||||
{ key: 'space-gray', value: 'Space Gray' }
|
||||
];
|
||||
|
||||
class UISettings extends Component {
|
||||
|
||||
//
|
||||
@@ -184,6 +199,21 @@ class UISettings extends Component {
|
||||
</FieldSet>
|
||||
|
||||
<FieldSet legend={translate('Style')}>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Theme')}</FormLabel>
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="theme"
|
||||
helpText={translate('ThemeHelpText', ['Theme.Park'])}
|
||||
inlineLink="https://github.com/GilbN/theme.park"
|
||||
tooltip="Theme.Park Github"
|
||||
helpTextWarning={translate('ThemeHelpTextWarning')}
|
||||
values={themeOptions}
|
||||
onChange={onInputChange}
|
||||
{...settings.theme}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('SettingsEnableColorImpairedMode')}</FormLabel>
|
||||
<FormInputGroup
|
||||
|
||||
@@ -10,7 +10,7 @@ import {
|
||||
import getSectionState from 'Utilities/State/getSectionState';
|
||||
import updateSectionState from 'Utilities/State/updateSectionState';
|
||||
|
||||
const blacklistedProperties = [
|
||||
const omittedProperties = [
|
||||
'section',
|
||||
'id'
|
||||
];
|
||||
@@ -31,7 +31,7 @@ export default function createHandleActions(handlers, defaultState, section) {
|
||||
|
||||
if (section === baseSection) {
|
||||
const newState = Object.assign(getSectionState(state, payloadSection),
|
||||
_.omit(payload, blacklistedProperties));
|
||||
_.omit(payload, omittedProperties));
|
||||
|
||||
return updateSectionState(state, payloadSection, newState);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,9 @@ export default {
|
||||
const promise = createAjaxRequest({
|
||||
method: 'PUT',
|
||||
url: '/qualityDefinition/update',
|
||||
data: JSON.stringify(upatedDefinitions)
|
||||
data: JSON.stringify(upatedDefinitions),
|
||||
contentType: 'application/json',
|
||||
dataType: 'json'
|
||||
}).request;
|
||||
|
||||
promise.done((data) => {
|
||||
|
||||
@@ -123,6 +123,7 @@ export const actionHandlers = handleThunks({
|
||||
const promise = createAjaxRequest({
|
||||
url: '/movie',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(newMovie)
|
||||
}).request;
|
||||
|
||||
@@ -15,7 +15,7 @@ import createSetTableOptionReducer from './Creators/Reducers/createSetTableOptio
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'blacklist';
|
||||
export const section = 'blocklist';
|
||||
|
||||
//
|
||||
// State
|
||||
@@ -83,41 +83,41 @@ export const defaultState = {
|
||||
};
|
||||
|
||||
export const persistState = [
|
||||
'blacklist.pageSize',
|
||||
'blacklist.sortKey',
|
||||
'blacklist.sortDirection',
|
||||
'blacklist.columns'
|
||||
'blocklist.pageSize',
|
||||
'blocklist.sortKey',
|
||||
'blocklist.sortDirection',
|
||||
'blocklist.columns'
|
||||
];
|
||||
|
||||
//
|
||||
// Action Types
|
||||
|
||||
export const FETCH_BLACKLIST = 'blacklist/fetchBlacklist';
|
||||
export const GOTO_FIRST_BLACKLIST_PAGE = 'blacklist/gotoBlacklistFirstPage';
|
||||
export const GOTO_PREVIOUS_BLACKLIST_PAGE = 'blacklist/gotoBlacklistPreviousPage';
|
||||
export const GOTO_NEXT_BLACKLIST_PAGE = 'blacklist/gotoBlacklistNextPage';
|
||||
export const GOTO_LAST_BLACKLIST_PAGE = 'blacklist/gotoBlacklistLastPage';
|
||||
export const GOTO_BLACKLIST_PAGE = 'blacklist/gotoBlacklistPage';
|
||||
export const SET_BLACKLIST_SORT = 'blacklist/setBlacklistSort';
|
||||
export const SET_BLACKLIST_TABLE_OPTION = 'blacklist/setBlacklistTableOption';
|
||||
export const REMOVE_BLACKLIST_ITEM = 'blacklist/removeBlacklistItem';
|
||||
export const REMOVE_BLACKLIST_ITEMS = 'blacklist/removeBlacklistItems';
|
||||
export const CLEAR_BLACKLIST = 'blacklist/clearBlacklist';
|
||||
export const FETCH_BLOCKLIST = 'blocklist/fetchBlocklist';
|
||||
export const GOTO_FIRST_BLOCKLIST_PAGE = 'blocklist/gotoBlocklistFirstPage';
|
||||
export const GOTO_PREVIOUS_BLOCKLIST_PAGE = 'blocklist/gotoBlocklistPreviousPage';
|
||||
export const GOTO_NEXT_BLOCKLIST_PAGE = 'blocklist/gotoBlocklistNextPage';
|
||||
export const GOTO_LAST_BLOCKLIST_PAGE = 'blocklist/gotoBlocklistLastPage';
|
||||
export const GOTO_BLOCKLIST_PAGE = 'blocklist/gotoBlocklistPage';
|
||||
export const SET_BLOCKLIST_SORT = 'blocklist/setBlocklistSort';
|
||||
export const SET_BLOCKLIST_TABLE_OPTION = 'blocklist/setBlocklistTableOption';
|
||||
export const REMOVE_BLOCKLIST_ITEM = 'blocklist/removeBlocklistItem';
|
||||
export const REMOVE_BLOCKLIST_ITEMS = 'blocklist/removeBlocklistItems';
|
||||
export const CLEAR_BLOCKLIST = 'blocklist/clearBlocklist';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchBlacklist = createThunk(FETCH_BLACKLIST);
|
||||
export const gotoBlacklistFirstPage = createThunk(GOTO_FIRST_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistPreviousPage = createThunk(GOTO_PREVIOUS_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistNextPage = createThunk(GOTO_NEXT_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistLastPage = createThunk(GOTO_LAST_BLACKLIST_PAGE);
|
||||
export const gotoBlacklistPage = createThunk(GOTO_BLACKLIST_PAGE);
|
||||
export const setBlacklistSort = createThunk(SET_BLACKLIST_SORT);
|
||||
export const setBlacklistTableOption = createAction(SET_BLACKLIST_TABLE_OPTION);
|
||||
export const removeBlacklistItem = createThunk(REMOVE_BLACKLIST_ITEM);
|
||||
export const removeBlacklistItems = createThunk(REMOVE_BLACKLIST_ITEMS);
|
||||
export const clearBlacklist = createAction(CLEAR_BLACKLIST);
|
||||
export const fetchBlocklist = createThunk(FETCH_BLOCKLIST);
|
||||
export const gotoBlocklistFirstPage = createThunk(GOTO_FIRST_BLOCKLIST_PAGE);
|
||||
export const gotoBlocklistPreviousPage = createThunk(GOTO_PREVIOUS_BLOCKLIST_PAGE);
|
||||
export const gotoBlocklistNextPage = createThunk(GOTO_NEXT_BLOCKLIST_PAGE);
|
||||
export const gotoBlocklistLastPage = createThunk(GOTO_LAST_BLOCKLIST_PAGE);
|
||||
export const gotoBlocklistPage = createThunk(GOTO_BLOCKLIST_PAGE);
|
||||
export const setBlocklistSort = createThunk(SET_BLOCKLIST_SORT);
|
||||
export const setBlocklistTableOption = createAction(SET_BLOCKLIST_TABLE_OPTION);
|
||||
export const removeBlocklistItem = createThunk(REMOVE_BLOCKLIST_ITEM);
|
||||
export const removeBlocklistItems = createThunk(REMOVE_BLOCKLIST_ITEMS);
|
||||
export const clearBlocklist = createAction(CLEAR_BLOCKLIST);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
@@ -125,21 +125,21 @@ export const clearBlacklist = createAction(CLEAR_BLACKLIST);
|
||||
export const actionHandlers = handleThunks({
|
||||
...createServerSideCollectionHandlers(
|
||||
section,
|
||||
'/blacklist',
|
||||
fetchBlacklist,
|
||||
'/blocklist',
|
||||
fetchBlocklist,
|
||||
{
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_BLACKLIST,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_BLACKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_BLACKLIST_SORT
|
||||
[serverSideCollectionHandlers.FETCH]: FETCH_BLOCKLIST,
|
||||
[serverSideCollectionHandlers.FIRST_PAGE]: GOTO_FIRST_BLOCKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.PREVIOUS_PAGE]: GOTO_PREVIOUS_BLOCKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.NEXT_PAGE]: GOTO_NEXT_BLOCKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.LAST_PAGE]: GOTO_LAST_BLOCKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.EXACT_PAGE]: GOTO_BLOCKLIST_PAGE,
|
||||
[serverSideCollectionHandlers.SORT]: SET_BLOCKLIST_SORT
|
||||
}),
|
||||
|
||||
[REMOVE_BLACKLIST_ITEM]: createRemoveItemHandler(section, '/blacklist'),
|
||||
[REMOVE_BLOCKLIST_ITEM]: createRemoveItemHandler(section, '/blocklist'),
|
||||
|
||||
[REMOVE_BLACKLIST_ITEMS]: function(getState, payload, dispatch) {
|
||||
[REMOVE_BLOCKLIST_ITEMS]: function(getState, payload, dispatch) {
|
||||
const {
|
||||
ids
|
||||
} = payload;
|
||||
@@ -157,15 +157,16 @@ export const actionHandlers = handleThunks({
|
||||
]));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: '/blacklist/bulk',
|
||||
url: '/blocklist/bulk',
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ ids })
|
||||
}).request;
|
||||
|
||||
promise.done((data) => {
|
||||
// Don't use batchActions with thunks
|
||||
dispatch(fetchBlacklist());
|
||||
dispatch(fetchBlocklist());
|
||||
|
||||
dispatch(set({ section, isRemoving: false }));
|
||||
});
|
||||
@@ -191,9 +192,9 @@ export const actionHandlers = handleThunks({
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[SET_BLACKLIST_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
[SET_BLOCKLIST_TABLE_OPTION]: createSetTableOptionReducer(section),
|
||||
|
||||
[CLEAR_BLACKLIST]: createClearReducer(section, {
|
||||
[CLEAR_BLOCKLIST]: createClearReducer(section, {
|
||||
isFetching: false,
|
||||
isPopulated: false,
|
||||
error: null,
|
||||
@@ -139,7 +139,8 @@ export function executeCommandHelper( payload, dispatch) {
|
||||
const promise = createAjaxRequest({
|
||||
url: '/command',
|
||||
method: 'POST',
|
||||
data: JSON.stringify(payload)
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
}).request;
|
||||
|
||||
return promise.then((data) => {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import * as addMovie from './addMovieActions';
|
||||
import * as app from './appActions';
|
||||
import * as blacklist from './blacklistActions';
|
||||
import * as blocklist from './blocklistActions';
|
||||
import * as calendar from './calendarActions';
|
||||
import * as captcha from './captchaActions';
|
||||
import * as commands from './commandActions';
|
||||
@@ -11,7 +11,7 @@ import * as history from './historyActions';
|
||||
import * as importMovie from './importMovieActions';
|
||||
import * as interactiveImportActions from './interactiveImportActions';
|
||||
import * as movies from './movieActions';
|
||||
import * as movieBlacklist from './movieBlacklistActions';
|
||||
import * as movieBlocklist from './movieBlocklistActions';
|
||||
import * as movieCredits from './movieCreditsActions';
|
||||
import * as movieFiles from './movieFileActions';
|
||||
import * as movieHistory from './movieHistoryActions';
|
||||
@@ -30,7 +30,7 @@ import * as tags from './tagActions';
|
||||
export default [
|
||||
addMovie,
|
||||
app,
|
||||
blacklist,
|
||||
blocklist,
|
||||
calendar,
|
||||
captcha,
|
||||
commands,
|
||||
@@ -49,7 +49,7 @@ export default [
|
||||
releases,
|
||||
rootFolders,
|
||||
movies,
|
||||
movieBlacklist,
|
||||
movieBlocklist,
|
||||
movieHistory,
|
||||
movieIndex,
|
||||
movieCredits,
|
||||
|
||||
@@ -8,7 +8,7 @@ import createHandleActions from './Creators/createHandleActions';
|
||||
//
|
||||
// Variables
|
||||
|
||||
export const section = 'movieBlacklist';
|
||||
export const section = 'movieBlocklist';
|
||||
|
||||
//
|
||||
// State
|
||||
@@ -23,25 +23,25 @@ export const defaultState = {
|
||||
//
|
||||
// Actions Types
|
||||
|
||||
export const FETCH_MOVIE_BLACKLIST = 'movieBlacklist/fetchMovieBlacklist';
|
||||
export const CLEAR_MOVIE_BLACKLIST = 'movieBlacklist/clearMovieBlacklist';
|
||||
export const FETCH_MOVIE_BLOCKLIST = 'movieBlocklist/fetchMovieBlocklist';
|
||||
export const CLEAR_MOVIE_BLOCKLIST = 'movieBlocklist/clearMovieBlocklist';
|
||||
|
||||
//
|
||||
// Action Creators
|
||||
|
||||
export const fetchMovieBlacklist = createThunk(FETCH_MOVIE_BLACKLIST);
|
||||
export const clearMovieBlacklist = createAction(CLEAR_MOVIE_BLACKLIST);
|
||||
export const fetchMovieBlocklist = createThunk(FETCH_MOVIE_BLOCKLIST);
|
||||
export const clearMovieBlocklist = createAction(CLEAR_MOVIE_BLOCKLIST);
|
||||
|
||||
//
|
||||
// Action Handlers
|
||||
|
||||
export const actionHandlers = handleThunks({
|
||||
|
||||
[FETCH_MOVIE_BLACKLIST]: function(getState, payload, dispatch) {
|
||||
[FETCH_MOVIE_BLOCKLIST]: function(getState, payload, dispatch) {
|
||||
dispatch(set({ section, isFetching: true }));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: '/blacklist/movie',
|
||||
url: '/blocklist/movie',
|
||||
data: payload
|
||||
}).request;
|
||||
|
||||
@@ -74,7 +74,7 @@ export const actionHandlers = handleThunks({
|
||||
|
||||
export const reducers = createHandleActions({
|
||||
|
||||
[CLEAR_MOVIE_BLACKLIST]: (state) => {
|
||||
[CLEAR_MOVIE_BLOCKLIST]: (state) => {
|
||||
return Object.assign({}, state, defaultState);
|
||||
}
|
||||
|
||||
@@ -78,7 +78,8 @@ export const actionHandlers = handleThunks({
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: `/history/failed/${historyId}`,
|
||||
method: 'POST'
|
||||
method: 'POST',
|
||||
dataType: 'json'
|
||||
}).request;
|
||||
|
||||
promise.done(() => {
|
||||
@@ -97,4 +98,3 @@ export const reducers = createHandleActions({
|
||||
}
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
|
||||
@@ -354,13 +354,13 @@ export const actionHandlers = handleThunks({
|
||||
const {
|
||||
id,
|
||||
remove,
|
||||
blacklist
|
||||
blocklist
|
||||
} = payload;
|
||||
|
||||
dispatch(updateItem({ section: paged, id, isRemoving: true }));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: `/queue/${id}?removeFromClient=${remove}&blacklist=${blacklist}`,
|
||||
url: `/queue/${id}?removeFromClient=${remove}&blocklist=${blocklist}`,
|
||||
method: 'DELETE'
|
||||
}).request;
|
||||
|
||||
@@ -377,7 +377,7 @@ export const actionHandlers = handleThunks({
|
||||
const {
|
||||
ids,
|
||||
remove,
|
||||
blacklist
|
||||
blocklist
|
||||
} = payload;
|
||||
|
||||
dispatch(batchActions([
|
||||
@@ -393,9 +393,10 @@ export const actionHandlers = handleThunks({
|
||||
]));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: `/queue/bulk?removeFromClient=${remove}&blacklist=${blacklist}`,
|
||||
url: `/queue/bulk?removeFromClient=${remove}&blocklist=${blocklist}`,
|
||||
method: 'DELETE',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify({ ids })
|
||||
}).request;
|
||||
|
||||
@@ -453,4 +454,3 @@ export const reducers = createHandleActions({
|
||||
})
|
||||
|
||||
}, defaultState, section);
|
||||
|
||||
|
||||
@@ -240,6 +240,7 @@ export const actionHandlers = handleThunks({
|
||||
const promise = createAjaxRequest({
|
||||
url: '/release',
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
contentType: 'application/json',
|
||||
data: JSON.stringify(payload)
|
||||
}).request;
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user