mirror of
https://github.com/Radarr/Radarr.git
synced 2026-04-18 21:35:51 -04:00
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 982e3c14d3 |
+1
-12
@@ -110,13 +110,13 @@ dotnet_diagnostic.SA1643.severity = none
|
|||||||
dotnet_diagnostic.SA1648.severity = none
|
dotnet_diagnostic.SA1648.severity = none
|
||||||
dotnet_diagnostic.SA1649.severity = none
|
dotnet_diagnostic.SA1649.severity = none
|
||||||
dotnet_diagnostic.SA1651.severity = none
|
dotnet_diagnostic.SA1651.severity = none
|
||||||
|
dotnet_diagnostic.SX1101.severity = warning
|
||||||
dotnet_diagnostic.SX1309.severity = warning
|
dotnet_diagnostic.SX1309.severity = warning
|
||||||
|
|
||||||
# Microsoft Analyzers that fail and need to be sorted thru
|
# Microsoft Analyzers that fail and need to be sorted thru
|
||||||
dotnet_diagnostic.ASP0000.severity = suggestion
|
dotnet_diagnostic.ASP0000.severity = suggestion
|
||||||
dotnet_diagnostic.CA1000.severity = suggestion
|
dotnet_diagnostic.CA1000.severity = suggestion
|
||||||
dotnet_diagnostic.CA1001.severity = suggestion
|
dotnet_diagnostic.CA1001.severity = suggestion
|
||||||
dotnet_diagnostic.CA1002.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1003.severity = suggestion
|
dotnet_diagnostic.CA1003.severity = suggestion
|
||||||
dotnet_diagnostic.CA1008.severity = suggestion
|
dotnet_diagnostic.CA1008.severity = suggestion
|
||||||
dotnet_diagnostic.CA1010.severity = suggestion
|
dotnet_diagnostic.CA1010.severity = suggestion
|
||||||
@@ -163,16 +163,10 @@ dotnet_diagnostic.CA1304.severity = suggestion
|
|||||||
dotnet_diagnostic.CA1305.severity = suggestion
|
dotnet_diagnostic.CA1305.severity = suggestion
|
||||||
dotnet_diagnostic.CA1307.severity = suggestion
|
dotnet_diagnostic.CA1307.severity = suggestion
|
||||||
dotnet_diagnostic.CA1308.severity = suggestion
|
dotnet_diagnostic.CA1308.severity = suggestion
|
||||||
dotnet_diagnostic.CA1309.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1310.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1401.severity = suggestion
|
dotnet_diagnostic.CA1401.severity = suggestion
|
||||||
dotnet_diagnostic.CA1416.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1507.severity = suggestion
|
dotnet_diagnostic.CA1507.severity = suggestion
|
||||||
dotnet_diagnostic.CA1508.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1707.severity = suggestion
|
dotnet_diagnostic.CA1707.severity = suggestion
|
||||||
dotnet_diagnostic.CA1708.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1710.severity = suggestion
|
dotnet_diagnostic.CA1710.severity = suggestion
|
||||||
dotnet_diagnostic.CA1711.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1712.severity = suggestion
|
dotnet_diagnostic.CA1712.severity = suggestion
|
||||||
dotnet_diagnostic.CA1714.severity = suggestion
|
dotnet_diagnostic.CA1714.severity = suggestion
|
||||||
dotnet_diagnostic.CA1715.severity = suggestion
|
dotnet_diagnostic.CA1715.severity = suggestion
|
||||||
@@ -181,14 +175,12 @@ dotnet_diagnostic.CA1717.severity = suggestion
|
|||||||
dotnet_diagnostic.CA1720.severity = suggestion
|
dotnet_diagnostic.CA1720.severity = suggestion
|
||||||
dotnet_diagnostic.CA1721.severity = suggestion
|
dotnet_diagnostic.CA1721.severity = suggestion
|
||||||
dotnet_diagnostic.CA1724.severity = suggestion
|
dotnet_diagnostic.CA1724.severity = suggestion
|
||||||
dotnet_diagnostic.CA1725.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1801.severity = suggestion
|
dotnet_diagnostic.CA1801.severity = suggestion
|
||||||
dotnet_diagnostic.CA1802.severity = suggestion
|
dotnet_diagnostic.CA1802.severity = suggestion
|
||||||
dotnet_diagnostic.CA1805.severity = suggestion
|
dotnet_diagnostic.CA1805.severity = suggestion
|
||||||
dotnet_diagnostic.CA1806.severity = suggestion
|
dotnet_diagnostic.CA1806.severity = suggestion
|
||||||
dotnet_diagnostic.CA1810.severity = suggestion
|
dotnet_diagnostic.CA1810.severity = suggestion
|
||||||
dotnet_diagnostic.CA1812.severity = suggestion
|
dotnet_diagnostic.CA1812.severity = suggestion
|
||||||
dotnet_diagnostic.CA1813.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA1814.severity = suggestion
|
dotnet_diagnostic.CA1814.severity = suggestion
|
||||||
dotnet_diagnostic.CA1815.severity = suggestion
|
dotnet_diagnostic.CA1815.severity = suggestion
|
||||||
dotnet_diagnostic.CA1816.severity = suggestion
|
dotnet_diagnostic.CA1816.severity = suggestion
|
||||||
@@ -210,7 +202,6 @@ dotnet_diagnostic.CA2101.severity = suggestion
|
|||||||
dotnet_diagnostic.CA2119.severity = suggestion
|
dotnet_diagnostic.CA2119.severity = suggestion
|
||||||
dotnet_diagnostic.CA2153.severity = suggestion
|
dotnet_diagnostic.CA2153.severity = suggestion
|
||||||
dotnet_diagnostic.CA2200.severity = suggestion
|
dotnet_diagnostic.CA2200.severity = suggestion
|
||||||
dotnet_diagnostic.CA2201.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA2207.severity = suggestion
|
dotnet_diagnostic.CA2207.severity = suggestion
|
||||||
dotnet_diagnostic.CA2208.severity = suggestion
|
dotnet_diagnostic.CA2208.severity = suggestion
|
||||||
dotnet_diagnostic.CA2211.severity = suggestion
|
dotnet_diagnostic.CA2211.severity = suggestion
|
||||||
@@ -256,8 +247,6 @@ dotnet_diagnostic.CA5374.severity = suggestion
|
|||||||
dotnet_diagnostic.CA5379.severity = suggestion
|
dotnet_diagnostic.CA5379.severity = suggestion
|
||||||
dotnet_diagnostic.CA5384.severity = suggestion
|
dotnet_diagnostic.CA5384.severity = suggestion
|
||||||
dotnet_diagnostic.CA5385.severity = suggestion
|
dotnet_diagnostic.CA5385.severity = suggestion
|
||||||
dotnet_diagnostic.CA5392.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA5394.severity = suggestion
|
|
||||||
dotnet_diagnostic.CA5397.severity = suggestion
|
dotnet_diagnostic.CA5397.severity = suggestion
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
---
|
||||||
|
name: Bug Report
|
||||||
|
about: 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!
|
||||||
|
title: ''
|
||||||
|
labels: bug
|
||||||
|
assignees: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**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.10]
|
||||||
|
- Docker: [Yes/No]
|
||||||
|
- Mono or.NET Core Version: [e.g. Mono 5.8 or .Net Core 3.1.10] (found under System -> Status)
|
||||||
|
- Browser and Version [e.g. chrome 86.0.4240.198] (Only needed for UI issues)
|
||||||
|
- Radarr Version [e.g. 3.0.0.2956]
|
||||||
|
- Radarr Branch [e.g. master]
|
||||||
|
|
||||||
|
**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!**
|
||||||
@@ -1,73 +0,0 @@
|
|||||||
name: Bug Report
|
|
||||||
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: Trace Logs?
|
|
||||||
description: |
|
|
||||||
Trace Logs (https://wiki.servarr.com/radarr/troubleshooting#logging-and-log-files)
|
|
||||||
***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.
|
|
||||||
Additionally, any additional info? Screenshots? References? Anything that will give us more context about the issue you are encountering!
|
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: false
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Support via Discord
|
- name: Support via Discord
|
||||||
url: https://radarr.video/discord
|
url: https://discord.gg/r5wJPt9
|
||||||
about: Chat with users and devs on support and setup related topics.
|
about: Chat with users and devs on support and setup related topics.
|
||||||
- name: Support via Reddit
|
- name: Support via Reddit
|
||||||
url: https://reddit.com/r/radarr
|
url: https://reddit.com/r/radarr
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
---
|
||||||
|
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.
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
name: Feature Request
|
|
||||||
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
|
|
||||||
@@ -1,16 +1,15 @@
|
|||||||
#### Database Migration
|
#### Database Migration
|
||||||
YES - XXXX | NO
|
YES | NO
|
||||||
|
|
||||||
#### Description
|
#### Description
|
||||||
A few sentences describing the overall goals of the pull request's commits.
|
|
||||||
|
|
||||||
#### Screenshot (if UI related)
|
#### Screenshot (if UI related)
|
||||||
|
|
||||||
#### Todos
|
#### Todos
|
||||||
- [ ] Tests
|
- [ ] Tests
|
||||||
- [ ] Translation Keys (./src/NzbDrone.Core/Localization/Core/en.json)
|
- [ ] Translation Keys
|
||||||
- [ ] [Wiki Updates](https://wiki.servarr.com)
|
- [ ] Wiki Updates
|
||||||
|
|
||||||
#### Issues Fixed or Closed by this PR
|
#### Issues Fixed or Closed by this PR
|
||||||
|
|
||||||
* Fixes #XXXX
|
* Fixes #XXXX
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
todo:
|
||||||
|
keyword: "TODO"
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
|
||||||
+4
-3
@@ -4,12 +4,13 @@ daysUntilStale: 60
|
|||||||
daysUntilClose: 7
|
daysUntilClose: 7
|
||||||
# Issues with these labels will never be considered stale
|
# Issues with these labels will never be considered stale
|
||||||
exemptLabels:
|
exemptLabels:
|
||||||
- feature request #legacy
|
- feature request
|
||||||
- 'Type: Feature Request'
|
- parser
|
||||||
- 'Status: Confirmed'
|
- confirmed
|
||||||
- sonarr-pull
|
- sonarr-pull
|
||||||
- lidarr-pull
|
- lidarr-pull
|
||||||
- readarr-pull
|
- readarr-pull
|
||||||
|
- v3
|
||||||
# Label to use when marking an issue as stale
|
# Label to use when marking an issue as stale
|
||||||
staleLabel: stale
|
staleLabel: stale
|
||||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||||
|
|||||||
@@ -0,0 +1,13 @@
|
|||||||
|
# Configuration for support-requests - https://github.com/dessant/support-requests
|
||||||
|
|
||||||
|
# Label used to mark issues as support requests
|
||||||
|
supportLabel: support
|
||||||
|
# Comment to post on issues marked as support requests. Add a link
|
||||||
|
# to a support page, or set to `false` to disable
|
||||||
|
supportComment: >
|
||||||
|
We use the issue tracker exclusively for bug reports and feature requests.
|
||||||
|
However, this issue appears to be a support request. Please hop over onto our [Discord](https://discord.gg/r5wJPt9) or [Subreddit](https://reddit.com/r/radarr)
|
||||||
|
# Whether to close issues marked as support requests
|
||||||
|
close: true
|
||||||
|
# Whether to lock issues marked as support requests
|
||||||
|
lock: false
|
||||||
@@ -1,41 +0,0 @@
|
|||||||
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,21 +0,0 @@
|
|||||||
name: 'Support requests'
|
|
||||||
|
|
||||||
on:
|
|
||||||
issues:
|
|
||||||
types: [labeled, unlabeled, reopened]
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
support:
|
|
||||||
runs-on: ubuntu-latest
|
|
||||||
steps:
|
|
||||||
- uses: dessant/support-requests@v2
|
|
||||||
with:
|
|
||||||
github-token: ${{ github.token }}
|
|
||||||
support-label: 'Type: Support'
|
|
||||||
issue-comment: >
|
|
||||||
:wave: @{issue-author}, we use the issue tracker exclusively
|
|
||||||
for bug reports and feature requests. However, this issue appears
|
|
||||||
to be a support request. Please hop over onto our [Discord](https://radarr.video/discord)
|
|
||||||
or [Subreddit](https://reddit.com/r/radarr)
|
|
||||||
close-issue: true
|
|
||||||
lock-issue: false
|
|
||||||
+42
-6
@@ -1,13 +1,49 @@
|
|||||||
# 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.
|
We're always looking for people to help make Radarr even better, there are a number of ways to contribute.
|
||||||
|
|
||||||
This file has been moved to the wiki for the latest details please see the [contributing wiki page](https://wiki.servarr.com/radarr/contributing).
|
## Documentation ##
|
||||||
|
Setup guides, FAQ, the more information we have on the [wiki](https://wiki.servarr.com/Radarr) the better.
|
||||||
|
|
||||||
## Documentation
|
## Development ##
|
||||||
|
|
||||||
Setup guides, [FAQ](https://wiki.servarr.com/radarr/faq), the more information we have on the [wiki](https://wiki.servarr.com/radarr) the better.
|
### 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 10.X.X or higher)
|
||||||
|
- [Yarn](https://yarnpkg.com/)
|
||||||
|
- .NET Core 3.1.
|
||||||
|
|
||||||
## Development
|
### Getting started ###
|
||||||
|
|
||||||
See the [Wiki Page](https://wiki.servarr.com/radarr/contributing)
|
1. Fork Radarr
|
||||||
|
2. Clone the repository into your development machine. [*info*](https://help.github.com/articles/working-with-repositories)
|
||||||
|
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 `netcoreapp31`
|
||||||
|
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.
|
||||||
|
|||||||
@@ -1,21 +1,19 @@
|
|||||||
# Radarr
|
# Radarr
|
||||||
|
|
||||||
[](https://dev.azure.com/Radarr/Radarr/_build/latest?definitionId=1&branchName=develop)
|
[](https://dev.azure.com/Radarr/Radarr/_build/latest?definitionId=1&branchName=develop)
|
||||||
[](https://translate.servarr.com/engage/radarr/?utm_source=widget)
|
[](https://translate.servarr.com/engage/radarr/?utm_source=widget)
|
||||||
[](https://wiki.servarr.com/radarr/installation#docker)
|
[](https://wiki.servarr.com/Radarr_Installation#Docker)
|
||||||

|

|
||||||
[](#backers)
|
[](#backers)
|
||||||
[](#sponsors)
|
[](#sponsors)
|
||||||
[](#mega-sponsors)
|
|
||||||
|
|
||||||
Radarr is a movie collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new movies and will interface with clients and indexers to grab, sort, and rename them. It can also be configured to automatically upgrade the quality of existing files in the library when a better quality format becomes available.
|
Radarr is a movie collection manager for Usenet and BitTorrent users. It can monitor multiple RSS feeds for new movies and will interface with clients and indexers to grab, sort, and rename them. It can also be configured to automatically upgrade the quality of existing files in the library when a better quality format becomes available.
|
||||||
Note that only one type of a given movie is supported. If you want both an 4k version and 1080p version of a given movie you will need multiple instances.
|
|
||||||
|
|
||||||
## Major Features Include
|
## Major Features Include:
|
||||||
|
|
||||||
* Adding new movies with lots of information, such as trailers, ratings, etc.
|
* Adding new movies with lots of information, such as trailers, ratings, etc.
|
||||||
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
* Support for major platforms: Windows, Linux, macOS, Raspberry Pi, etc.
|
||||||
* Can watch for better quality of the movies you have and do an automatic upgrade. *e.g. from DVD to Blu-Ray*
|
* Can watch for better quality of the movies you have and do an automatic upgrade. *eg. from DVD to Blu-Ray*
|
||||||
* Automatic failed download handling will try another release if one fails
|
* Automatic failed download handling will try another release if one fails
|
||||||
* Manual search so you can pick any release or to see why a release was not downloaded automatically
|
* Manual search so you can pick any release or to see why a release was not downloaded automatically
|
||||||
* Full integration with SABnzbd and NZBGet
|
* Full integration with SABnzbd and NZBGet
|
||||||
@@ -23,60 +21,57 @@ Note that only one type of a given movie is supported. If you want both an 4k ve
|
|||||||
* Automatically importing downloaded movies
|
* Automatically importing downloaded movies
|
||||||
* Recognizing Special Editions, Director's Cut, etc.
|
* Recognizing Special Editions, Director's Cut, etc.
|
||||||
* Identifying releases with hardcoded subs
|
* Identifying releases with hardcoded subs
|
||||||
* Identifying releases with AKA movie names
|
* QBittorrent, Deluge, rTorrent, Transmission, uTorrent, and other download clients are supported
|
||||||
* SABnzbd, NZBGet, QBittorrent, Deluge, rTorrent, Transmission, uTorrent, and other download clients are supported and integrated
|
* Full integration with Kodi, Plex (notification, library update)
|
||||||
* Full integration with Kodi and Plex (notifications, library updates)
|
* A beautiful UI
|
||||||
* Importing Metadata such as trailers or subtitles
|
* Importing Metadata such as trailers or subtitles
|
||||||
* Adding metadata such as posters and information for Kodi and others to use
|
* Adding metadata such as posters and information for Kodi and others to use
|
||||||
* Advanced customization for profiles, such that Radarr will always download the copy you want
|
* Advanced customization for profiles, such that Radarr will always download the copy you want
|
||||||
* A beautiful UI
|
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
[](https://wiki.servarr.com/radarr)
|
|
||||||
[](https://radarr.video/discord)
|
|
||||||
[](https://www.reddit.com/r/Radarr)
|
|
||||||
|
|
||||||
Note: GitHub Issues are for Bugs and Feature Requests Only
|
Note: GitHub Issues are for Bugs and Feature Requests Only
|
||||||
|
|
||||||
|
[](https://discord.gg/r5wJPt9)
|
||||||
|
[](https://www.reddit.com/r/Radarr)
|
||||||
[](https://github.com/Radarr/Radarr/issues)
|
[](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=)
|
||||||
|
|
||||||
## Contributors & Developers
|
## Contributors & Developers
|
||||||
|
|
||||||
[API Documentation](https://radarr.video/docs/api/)
|
[API Documentation](https://radarr.video/docs/api/)
|
||||||
|
|
||||||
This project exists thanks to all the people who contribute.
|
This project exists thanks to all the people who contribute. [Contribute](CONTRIBUTING.md).
|
||||||
- [Contribute (GitHub)](CONTRIBUTING.md)
|
<a href="https://github.com/Radarr/Radarr/graphs/contributors"><img src="https://opencollective.com/Radarr/contributors.svg?width=890&button=false" /></a>
|
||||||
- [Contribution (Wiki Article)](https://wiki.servarr.com/radarr/contributing)
|
|
||||||
|
|
||||||
[](https://github.com/Radarr/Radarr/graphs/contributors)
|
|
||||||
|
|
||||||
## Backers
|
## Backers
|
||||||
|
|
||||||
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Radarr#backer)
|
Thank you to all our backers! 🙏 [Become a backer](https://opencollective.com/Radarr#backer)
|
||||||
|
|
||||||
[](https://opencollective.com/Radarr#backer)
|
<img src="https://opencollective.com/Radarr/backers.svg?width=890"></a>
|
||||||
|
|
||||||
## Sponsors
|
## Sponsors
|
||||||
|
|
||||||
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/Radarr#sponsor)
|
Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [Become a sponsor](https://opencollective.com/Radarr#sponsor)
|
||||||
|
|
||||||
[](https://opencollective.com/Radarr#sponsor)
|
<img src="https://opencollective.com/Radarr/sponsors.svg?width=890"></a>
|
||||||
|
|
||||||
## Mega Sponsors
|
## Mega Sponsors
|
||||||
|
|
||||||
[](https://opencollective.com/Radarr#mega-sponsor)
|
<img src="https://opencollective.com/Radarr/tiers/mega-sponsor.svg?width=890"></a>
|
||||||
|
|
||||||
## JetBrains
|
## JetBrains
|
||||||
|
|
||||||
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
Thank you to [<img src="/Logo/jetbrains.svg" alt="JetBrains" width="32"> JetBrains](http://www.jetbrains.com/) for providing us with free licenses to their great tools.
|
||||||
|
|
||||||
* [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
* [<img src="/Logo/resharper.svg" alt="ReSharper" width="32"> ReSharper](http://www.jetbrains.com/resharper/)
|
||||||
* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
* [<img src="/Logo/webstorm.svg" alt="WebStorm" width="32"> WebStorm](http://www.jetbrains.com/webstorm/)
|
||||||
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
* [<img src="/Logo/rider.svg" alt="Rider" width="32"> Rider](http://www.jetbrains.com/rider/)
|
||||||
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
* [<img src="/Logo/dottrace.svg" alt="dotTrace" width="32"> dotTrace](http://www.jetbrains.com/dottrace/)
|
||||||
|
|
||||||
### License
|
### License
|
||||||
|
|
||||||
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)
|
||||||
* Copyright 2010-2022
|
* Copyright 2010-2021
|
||||||
|
|||||||
+103
-161
@@ -7,13 +7,13 @@ variables:
|
|||||||
outputFolder: './_output'
|
outputFolder: './_output'
|
||||||
artifactsFolder: './_artifacts'
|
artifactsFolder: './_artifacts'
|
||||||
testsFolder: './_tests'
|
testsFolder: './_tests'
|
||||||
majorVersion: '4.0.2'
|
majorVersion: '3.0.2'
|
||||||
minorVersion: $[counter('minorVersion', 2000)]
|
minorVersion: $[counter('minorVersion', 2000)]
|
||||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||||
sentryOrg: 'servarr'
|
sentryOrg: 'servarr'
|
||||||
sentryUrl: 'https://sentry.servarr.com'
|
sentryUrl: 'https://sentry.servarr.com'
|
||||||
dotnetVersion: '6.0.101'
|
dotnetVersion: '3.1.404'
|
||||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||||
|
|
||||||
trigger:
|
trigger:
|
||||||
@@ -23,12 +23,7 @@ trigger:
|
|||||||
- master
|
- master
|
||||||
|
|
||||||
pr:
|
pr:
|
||||||
branches:
|
- develop
|
||||||
include:
|
|
||||||
- develop
|
|
||||||
paths:
|
|
||||||
exclude:
|
|
||||||
- src/NzbDrone.Core/Localization/Core
|
|
||||||
|
|
||||||
stages:
|
stages:
|
||||||
- stage: Setup
|
- stage: Setup
|
||||||
@@ -64,21 +59,18 @@ stages:
|
|||||||
Linux:
|
Linux:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
enableAnalysis: 'true'
|
|
||||||
Mac:
|
Mac:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
imageName: 'macos-10.15'
|
imageName: 'macos-10.14'
|
||||||
enableAnalysis: 'false'
|
|
||||||
Windows:
|
Windows:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
enableAnalysis: 'false'
|
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
variables:
|
variables:
|
||||||
# Disable stylecop here - linting errors get caught by the analyze task
|
# Disable stylecop here - linting errors get caught by the analyze task
|
||||||
EnableAnalyzers: $(enableAnalysis)
|
EnableAnalyzers: 'false'
|
||||||
steps:
|
steps:
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
@@ -87,18 +79,7 @@ stages:
|
|||||||
displayName: 'Install .net core'
|
displayName: 'Install .net core'
|
||||||
inputs:
|
inputs:
|
||||||
version: $(dotnetVersion)
|
version: $(dotnetVersion)
|
||||||
- bash: |
|
- bash: ./build.sh --backend
|
||||||
BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props
|
|
||||||
echo $BUNDLEDVERSIONS
|
|
||||||
grep osx-x64 $BUNDLEDVERSIONS
|
|
||||||
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
|
|
||||||
echo "BSD already enabled"
|
|
||||||
else
|
|
||||||
echo "Enabling BSD support"
|
|
||||||
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' $BUNDLEDVERSIONS
|
|
||||||
fi
|
|
||||||
displayName: Enable FreeBSD Support
|
|
||||||
- bash: ./build.sh --backend --enable-bsd
|
|
||||||
displayName: Build Radarr Backend
|
displayName: Build Radarr Backend
|
||||||
- bash: |
|
- bash: |
|
||||||
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
|
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
|
||||||
@@ -111,23 +92,23 @@ stages:
|
|||||||
artifact: '$(osName)Backend'
|
artifact: '$(osName)Backend'
|
||||||
displayName: Publish Backend
|
displayName: Publish Backend
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/net6.0/win-x64/publish'
|
- publish: '$(testsFolder)/netcoreapp3.1/win-x64/publish'
|
||||||
artifact: WindowsCoreTests
|
artifact: WindowsCoreTests
|
||||||
displayName: Publish Windows Test Package
|
displayName: Publish Windows Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/net6.0/linux-x64/publish'
|
- publish: '$(testsFolder)/net462/linux-x64/publish'
|
||||||
|
artifact: LinuxTests
|
||||||
|
displayName: Publish Linux Mono Test Package
|
||||||
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
|
- publish: '$(testsFolder)/netcoreapp3.1/linux-x64/publish'
|
||||||
artifact: LinuxCoreTests
|
artifact: LinuxCoreTests
|
||||||
displayName: Publish Linux Test Package
|
displayName: Publish Linux Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
|
- publish: '$(testsFolder)/netcoreapp3.1/linux-musl-x64/publish'
|
||||||
artifact: LinuxMuslCoreTests
|
artifact: LinuxMuslCoreTests
|
||||||
displayName: Publish Linux Musl Test Package
|
displayName: Publish Linux Musl Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish'
|
- publish: '$(testsFolder)/netcoreapp3.1/osx-x64/publish'
|
||||||
artifact: FreebsdCoreTests
|
|
||||||
displayName: Publish FreeBSD Test Package
|
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
|
||||||
- publish: '$(testsFolder)/net6.0/osx-x64/publish'
|
|
||||||
artifact: MacCoreTests
|
artifact: MacCoreTests
|
||||||
displayName: Publish MacOS Test Package
|
displayName: Publish MacOS Test Package
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
@@ -144,7 +125,7 @@ stages:
|
|||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
Mac:
|
Mac:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
imageName: 'macos-10.15'
|
imageName: 'macos-10.14'
|
||||||
Windows:
|
Windows:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
@@ -154,7 +135,7 @@ stages:
|
|||||||
- task: NodeTool@0
|
- task: NodeTool@0
|
||||||
displayName: Set Node.js version
|
displayName: Set Node.js version
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: '12.x'
|
versionSpec: '10.x'
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
fetchDepth: 1
|
fetchDepth: 1
|
||||||
@@ -203,12 +184,12 @@ stages:
|
|||||||
- bash: ./build.sh --packages
|
- bash: ./build.sh --packages
|
||||||
displayName: Create Packages
|
displayName: Create Packages
|
||||||
- bash: |
|
- bash: |
|
||||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x86
|
setup/inno/ISCC.exe setup/radarr.iss //DFramework=netcoreapp3.1 //DRuntime=win-x86
|
||||||
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
cp setup/output/Radarr.*windows.netcoreapp3.1.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||||
displayName: Create .NET Core Windows installer
|
displayName: Create .NET Core Windows installer
|
||||||
- bash: |
|
- bash: |
|
||||||
setup/inno/ISCC.exe setup/radarr.iss //DFramework=net6.0 //DRuntime=win-x64
|
setup/inno/ISCC.exe setup/radarr.iss //DFramework=netcoreapp3.1 //DRuntime=win-x64
|
||||||
cp setup/output/Radarr.*windows.net6.0.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
cp setup/output/Radarr.*windows.netcoreapp3.1.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||||
displayName: Create .NET Core Windows installer
|
displayName: Create .NET Core Windows installer
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
- publish: $(Build.ArtifactStagingDirectory)
|
||||||
artifact: 'WindowsInstaller'
|
artifact: 'WindowsInstaller'
|
||||||
@@ -238,10 +219,9 @@ stages:
|
|||||||
artifactName: WindowsFrontend
|
artifactName: WindowsFrontend
|
||||||
targetPath: _output
|
targetPath: _output
|
||||||
displayName: Fetch Frontend
|
displayName: Fetch Frontend
|
||||||
- bash: ./build.sh --packages --enable-bsd
|
- bash: ./build.sh --packages
|
||||||
displayName: Create Packages
|
displayName: Create Packages
|
||||||
- bash: |
|
- bash: |
|
||||||
find . -name "ffprobe" -exec chmod a+x {} \;
|
|
||||||
find . -name "Radarr" -exec chmod a+x {} \;
|
find . -name "Radarr" -exec chmod a+x {} \;
|
||||||
find . -name "Radarr.Update" -exec chmod a+x {} \;
|
find . -name "Radarr.Update" -exec chmod a+x {} \;
|
||||||
displayName: Set executable bits
|
displayName: Set executable bits
|
||||||
@@ -251,44 +231,37 @@ stages:
|
|||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x64.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x64.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/win-x64/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Windows x86 Core zip
|
displayName: Create Windows x86 Core zip
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x86.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).windows-core-x86.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0
|
rootFolderOrFile: $(artifactsFolder)/win-x86/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create MacOS x64 Core app
|
displayName: Create MacOS Core app
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-x64.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-x64.zip'
|
||||||
archiveType: 'zip'
|
archiveType: 'zip'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0
|
rootFolderOrFile: $(artifactsFolder)/macos-app/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create MacOS x64 Core tar
|
displayName: Create MacOS Core tar
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-core-x64.tar.gz'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-core-x64.tar.gz'
|
||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/macos/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create MacOS arm64 Core app
|
displayName: Create Linux Mono tar
|
||||||
inputs:
|
inputs:
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-app-core-arm64.zip'
|
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).linux.tar.gz'
|
||||||
archiveType: 'zip'
|
|
||||||
includeRootFolder: false
|
|
||||||
rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0
|
|
||||||
- task: ArchiveFiles@2
|
|
||||||
displayName: Create MacOS arm64 Core tar
|
|
||||||
inputs:
|
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).osx-core-arm64.tar.gz'
|
|
||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-x64/net462
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Linux Core tar
|
displayName: Create Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -296,7 +269,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-x64/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create Linux Musl Core tar
|
displayName: Create Linux Musl Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -304,7 +277,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM32 Linux Core tar
|
displayName: Create ARM32 Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -312,15 +285,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-arm/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
|
||||||
displayName: Create ARM32 Linux Musl Core tar
|
|
||||||
inputs:
|
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).linux-musl-core-arm.tar.gz'
|
|
||||||
archiveType: 'tar'
|
|
||||||
tarCompression: 'gz'
|
|
||||||
includeRootFolder: false
|
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0
|
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM64 Linux Core tar
|
displayName: Create ARM64 Linux Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -328,7 +293,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-arm64/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
- task: ArchiveFiles@2
|
||||||
displayName: Create ARM64 Linux Musl Core tar
|
displayName: Create ARM64 Linux Musl Core tar
|
||||||
inputs:
|
inputs:
|
||||||
@@ -336,15 +301,7 @@ stages:
|
|||||||
archiveType: 'tar'
|
archiveType: 'tar'
|
||||||
tarCompression: 'gz'
|
tarCompression: 'gz'
|
||||||
includeRootFolder: false
|
includeRootFolder: false
|
||||||
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net6.0
|
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/netcoreapp3.1
|
||||||
- task: ArchiveFiles@2
|
|
||||||
displayName: Create FreeBSD Core Core tar
|
|
||||||
inputs:
|
|
||||||
archiveFile: '$(Build.ArtifactStagingDirectory)/Radarr.$(buildName).freebsd-core-x64.tar.gz'
|
|
||||||
archiveType: 'tar'
|
|
||||||
tarCompression: 'gz'
|
|
||||||
includeRootFolder: false
|
|
||||||
rootFolderOrFile: $(artifactsFolder)/freebsd-x64/net6.0
|
|
||||||
- publish: $(Build.ArtifactStagingDirectory)
|
- publish: $(Build.ArtifactStagingDirectory)
|
||||||
artifact: 'Packages'
|
artifact: 'Packages'
|
||||||
displayName: Publish Packages
|
displayName: Publish Packages
|
||||||
@@ -398,34 +355,24 @@ stages:
|
|||||||
displayName: Unit Native
|
displayName: Unit Native
|
||||||
dependsOn: Prepare
|
dependsOn: Prepare
|
||||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||||
workspace:
|
|
||||||
clean: all
|
|
||||||
|
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
MacCore:
|
MacCore:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
testName: 'MacCore'
|
testName: 'MacCore'
|
||||||
poolName: 'Azure Pipelines'
|
imageName: 'macos-10.14'
|
||||||
imageName: 'macos-10.15'
|
|
||||||
WindowsCore:
|
WindowsCore:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
testName: 'WindowsCore'
|
testName: 'WindowsCore'
|
||||||
poolName: 'Azure Pipelines'
|
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
LinuxCore:
|
LinuxCore:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
testName: 'LinuxCore'
|
testName: 'LinuxCore'
|
||||||
poolName: 'Azure Pipelines'
|
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
FreebsdCore:
|
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
||||||
osName: 'Linux'
|
|
||||||
testName: 'FreebsdCore'
|
|
||||||
poolName: 'FreeBSD'
|
|
||||||
imageName:
|
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
name: $(poolName)
|
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
|
|
||||||
steps:
|
steps:
|
||||||
@@ -434,20 +381,30 @@ stages:
|
|||||||
displayName: 'Install .net core'
|
displayName: 'Install .net core'
|
||||||
inputs:
|
inputs:
|
||||||
version: $(dotnetVersion)
|
version: $(dotnetVersion)
|
||||||
condition: ne(variables['poolName'], 'FreeBSD')
|
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
displayName: Download Test Artifact
|
displayName: Download Test Artifact
|
||||||
inputs:
|
inputs:
|
||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: '$(testName)Tests'
|
artifactName: '$(testName)Tests'
|
||||||
targetPath: $(testsFolder)
|
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['osName'], 'Linux'))
|
||||||
- powershell: Set-Service SCardSvr -StartupType Manual
|
- powershell: Set-Service SCardSvr -StartupType Manual
|
||||||
displayName: Enable Windows Test Service
|
displayName: Enable Windows Test Service
|
||||||
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
condition: and(succeeded(), eq(variables['osName'], 'Windows'))
|
||||||
- bash: |
|
- bash: |
|
||||||
chmod a+x _tests/ffprobe
|
SYMLINK=6_6_0
|
||||||
displayName: Make ffprobe Executable
|
MONOPREFIX=/Library/Frameworks/Mono.framework/Versions/$SYMLINK
|
||||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
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'))
|
||||||
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
||||||
displayName: Make Test Dummy Executable
|
displayName: Make Test Dummy Executable
|
||||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
||||||
@@ -471,10 +428,22 @@ stages:
|
|||||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
mono520:
|
||||||
|
testName: 'Mono 5.20'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-5.20
|
||||||
|
mono610:
|
||||||
|
testName: 'Mono 6.10'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-6.10
|
||||||
|
mono612:
|
||||||
|
testName: 'Mono 6.12'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-6.12
|
||||||
alpine:
|
alpine:
|
||||||
testName: 'Musl Net Core'
|
testName: 'Musl Net Core'
|
||||||
artifactName: LinuxMuslCoreTests
|
artifactName: LinuxMuslCoreTests
|
||||||
containerImage: ghcr.io/servarr/testimages:alpine
|
containerImage: servarr/testimages:alpine
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-18.04'
|
vmImage: 'ubuntu-18.04'
|
||||||
@@ -495,9 +464,6 @@ stages:
|
|||||||
buildType: 'current'
|
buildType: 'current'
|
||||||
artifactName: $(artifactName)
|
artifactName: $(artifactName)
|
||||||
targetPath: $(testsFolder)
|
targetPath: $(testsFolder)
|
||||||
- bash: |
|
|
||||||
chmod a+x _tests/ffprobe
|
|
||||||
displayName: Make ffprobe Executable
|
|
||||||
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
- bash: find ${TESTSFOLDER} -name "Radarr.Test.Dummy" -exec chmod a+x {} \;
|
||||||
displayName: Make Test Dummy Executable
|
displayName: Make Test Dummy Executable
|
||||||
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
|
||||||
@@ -541,23 +507,31 @@ stages:
|
|||||||
MacCore:
|
MacCore:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
testName: 'MacCore'
|
testName: 'MacCore'
|
||||||
imageName: 'macos-10.15'
|
imageName: 'macos-10.14'
|
||||||
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
pattern: 'Radarr.**.osx-core-x64.tar.gz'
|
||||||
WindowsCore:
|
WindowsCore:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
testName: 'WindowsCore'
|
testName: 'WindowsCore'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
pattern: 'Radarr.*.windows-core-x64.zip'
|
pattern: 'Radarr.**.windows-core-x64.zip'
|
||||||
LinuxCore:
|
LinuxCore:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
testName: 'LinuxCore'
|
testName: 'LinuxCore'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
pattern: 'Radarr.*.linux-core-x64.tar.gz'
|
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: $(imageName)
|
vmImage: $(imageName)
|
||||||
|
|
||||||
steps:
|
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
|
- task: UseDotNet@2
|
||||||
displayName: 'Install .net core'
|
displayName: 'Install .net core'
|
||||||
inputs:
|
inputs:
|
||||||
@@ -597,63 +571,32 @@ stages:
|
|||||||
failTaskOnFailedTests: true
|
failTaskOnFailedTests: true
|
||||||
displayName: Publish Test Results
|
displayName: Publish Test Results
|
||||||
|
|
||||||
- job: Integration_FreeBSD
|
|
||||||
displayName: Integration Native FreeBSD
|
|
||||||
dependsOn: Prepare
|
|
||||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
|
||||||
workspace:
|
|
||||||
clean: all
|
|
||||||
variables:
|
|
||||||
pattern: 'Radarr.*.freebsd-core-x64.tar.gz'
|
|
||||||
pool:
|
|
||||||
name: 'FreeBSD'
|
|
||||||
|
|
||||||
steps:
|
|
||||||
- checkout: none
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download Test Artifact
|
|
||||||
inputs:
|
|
||||||
buildType: 'current'
|
|
||||||
artifactName: 'FreebsdCoreTests'
|
|
||||||
targetPath: $(testsFolder)
|
|
||||||
- task: DownloadPipelineArtifact@2
|
|
||||||
displayName: Download Build Artifact
|
|
||||||
inputs:
|
|
||||||
buildType: 'current'
|
|
||||||
artifactName: Packages
|
|
||||||
itemPattern: '/$(pattern)'
|
|
||||||
targetPath: $(Build.ArtifactStagingDirectory)
|
|
||||||
- bash: |
|
|
||||||
mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
|
|
||||||
tar xf ${BUILD_ARTIFACTSTAGINGDIRECTORY}/$(pattern) -C ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
|
|
||||||
displayName: Extract Package
|
|
||||||
- bash: |
|
|
||||||
mkdir -p ./bin/
|
|
||||||
cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Radarr/. ./bin/
|
|
||||||
displayName: Move Package Contents
|
|
||||||
- bash: |
|
|
||||||
chmod a+x ${TESTSFOLDER}/test.sh
|
|
||||||
${TESTSFOLDER}/test.sh Linux Integration Test
|
|
||||||
displayName: Run Integration Tests
|
|
||||||
- task: PublishTestResults@2
|
|
||||||
inputs:
|
|
||||||
testResultsFormat: 'NUnit'
|
|
||||||
testResultsFiles: '**/TestResult.xml'
|
|
||||||
testRunTitle: 'FreeBSD Integration Tests'
|
|
||||||
failTaskOnFailedTests: true
|
|
||||||
displayName: Publish Test Results
|
|
||||||
|
|
||||||
- job: Integration_Docker
|
- job: Integration_Docker
|
||||||
displayName: Integration Docker
|
displayName: Integration Docker
|
||||||
dependsOn: Prepare
|
dependsOn: Prepare
|
||||||
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
condition: and(succeeded(), eq(dependencies.Prepare.outputs['setVar.backendNotUpdated'], '0'))
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
|
mono520:
|
||||||
|
testName: 'Mono 5.20'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-5.20
|
||||||
|
pattern: 'Radarr.**.linux.tar.gz'
|
||||||
|
mono610:
|
||||||
|
testName: 'Mono 6.10'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-6.10
|
||||||
|
pattern: 'Radarr.**.linux.tar.gz'
|
||||||
|
mono612:
|
||||||
|
testName: 'Mono 6.12'
|
||||||
|
artifactName: LinuxTests
|
||||||
|
containerImage: servarr/testimages:mono-6.12
|
||||||
|
pattern: 'Radarr.**.linux.tar.gz'
|
||||||
alpine:
|
alpine:
|
||||||
testName: 'Musl Net Core'
|
testName: 'Musl Net Core'
|
||||||
artifactName: LinuxMuslCoreTests
|
artifactName: LinuxMuslCoreTests
|
||||||
containerImage: ghcr.io/servarr/testimages:alpine
|
containerImage: servarr/testimages:alpine
|
||||||
pattern: 'Radarr.*.linux-musl-core-x64.tar.gz'
|
pattern: 'Radarr.**.linux-musl-core-x64.tar.gz'
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-18.04'
|
vmImage: 'ubuntu-18.04'
|
||||||
|
|
||||||
@@ -712,17 +655,17 @@ stages:
|
|||||||
Linux:
|
Linux:
|
||||||
osName: 'Linux'
|
osName: 'Linux'
|
||||||
imageName: 'ubuntu-18.04'
|
imageName: 'ubuntu-18.04'
|
||||||
pattern: 'Radarr.*.linux-core-x64.tar.gz'
|
pattern: 'Radarr.**.linux-core-x64.tar.gz'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
Mac:
|
Mac:
|
||||||
osName: 'Mac'
|
osName: 'Mac'
|
||||||
imageName: 'macos-10.15'
|
imageName: 'macos-10.14'
|
||||||
pattern: 'Radarr.*.osx-core-x64.tar.gz'
|
pattern: 'Radarr.**.osx-core-x64.tar.gz'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
Windows:
|
Windows:
|
||||||
osName: 'Windows'
|
osName: 'Windows'
|
||||||
imageName: 'windows-2019'
|
imageName: 'windows-2019'
|
||||||
pattern: 'Radarr.*.windows-core-x64.zip'
|
pattern: 'Radarr.**.windows-core-x64.zip'
|
||||||
failBuild: true
|
failBuild: true
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
@@ -814,7 +757,7 @@ stages:
|
|||||||
- task: NodeTool@0
|
- task: NodeTool@0
|
||||||
displayName: Set Node.js version
|
displayName: Set Node.js version
|
||||||
inputs:
|
inputs:
|
||||||
versionSpec: '12.x'
|
versionSpec: '10.x'
|
||||||
- checkout: self
|
- checkout: self
|
||||||
submodules: true
|
submodules: true
|
||||||
fetchDepth: 1
|
fetchDepth: 1
|
||||||
@@ -860,7 +803,6 @@ stages:
|
|||||||
|
|
||||||
variables:
|
variables:
|
||||||
disable.coverage.autogenerate: 'true'
|
disable.coverage.autogenerate: 'true'
|
||||||
EnableAnalyzers: 'false'
|
|
||||||
|
|
||||||
pool:
|
pool:
|
||||||
vmImage: windows-2019
|
vmImage: windows-2019
|
||||||
@@ -885,12 +827,12 @@ stages:
|
|||||||
projectVersion: '$(radarrVersion)'
|
projectVersion: '$(radarrVersion)'
|
||||||
extraProperties: |
|
extraProperties: |
|
||||||
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
|
sonar.exclusions=**/obj/**,**/*.dll,**/NzbDrone.Core.Test/Files/**/*,./frontend/**,**/ExternalModules/**,./src/Libraries/**
|
||||||
sonar.coverage.exclusions=**/Radarr.Api.V3/**/*
|
sonar.coverage.exclusions=**/Radarr.Api.V3/**/*,**/NzbDrone.Api/**/*,**/MonoTorrent/**/*,**/Marr.Data/**/*
|
||||||
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
sonar.cs.opencover.reportsPaths=$(Build.SourcesDirectory)/CoverageResults/**/coverage.opencover.xml
|
||||||
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
sonar.cs.nunit.reportsPaths=$(Build.SourcesDirectory)/TestResult.xml
|
||||||
- bash: |
|
- bash: |
|
||||||
./build.sh --backend -f net6.0 -r win-x64
|
./build.sh --backend -f netcoreapp3.1 -r win-x64
|
||||||
TEST_DIR=_tests/net6.0/win-x64/publish/ ./test.sh Windows Unit Coverage
|
TEST_DIR=_tests/netcoreapp3.1/win-x64/publish/ ./test.sh Windows Unit Coverage
|
||||||
displayName: Coverage Unit Tests
|
displayName: Coverage Unit Tests
|
||||||
- task: SonarCloudAnalyze@1
|
- task: SonarCloudAnalyze@1
|
||||||
condition: eq(variables['System.PullRequest.IsFork'], 'False')
|
condition: eq(variables['System.PullRequest.IsFork'], 'False')
|
||||||
@@ -920,7 +862,7 @@ stages:
|
|||||||
- job:
|
- job:
|
||||||
displayName: Discord Notification
|
displayName: Discord Notification
|
||||||
pool:
|
pool:
|
||||||
vmImage: 'ubuntu-18.04'
|
vmImage: 'windows-2019'
|
||||||
steps:
|
steps:
|
||||||
- task: DownloadPipelineArtifact@2
|
- task: DownloadPipelineArtifact@2
|
||||||
continueOnError: true
|
continueOnError: true
|
||||||
@@ -930,7 +872,7 @@ stages:
|
|||||||
artifactName: 'WindowsAutomationScreenshots'
|
artifactName: 'WindowsAutomationScreenshots'
|
||||||
targetPath: $(Build.SourcesDirectory)
|
targetPath: $(Build.SourcesDirectory)
|
||||||
- checkout: none
|
- checkout: none
|
||||||
- pwsh: |
|
- powershell: |
|
||||||
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Servarr/AzureDiscordNotify/master/DiscordNotify.ps1'))
|
iex ((New-Object System.Net.WebClient).DownloadString('https://raw.githubusercontent.com/Servarr/AzureDiscordNotify/master/DiscordNotify.ps1'))
|
||||||
env:
|
env:
|
||||||
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
#! /usr/bin/env bash
|
#! /bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
outputFolder='_output'
|
outputFolder='_output'
|
||||||
@@ -25,17 +25,6 @@ UpdateVersionNumber()
|
|||||||
fi
|
fi
|
||||||
}
|
}
|
||||||
|
|
||||||
EnableBsdSupport()
|
|
||||||
{
|
|
||||||
#todo enable sdk with
|
|
||||||
#SDK_PATH=$(dotnet --list-sdks | grep -P '5\.\d\.\d+' | head -1 | sed 's/\(5\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
|
|
||||||
# BUNDLED_VERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
|
|
||||||
|
|
||||||
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
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
|
|
||||||
LintUI()
|
LintUI()
|
||||||
{
|
{
|
||||||
ProgressStart 'ESLint'
|
ProgressStart 'ESLint'
|
||||||
@@ -86,11 +75,11 @@ YarnInstall()
|
|||||||
ProgressEnd 'yarn install'
|
ProgressEnd 'yarn install'
|
||||||
}
|
}
|
||||||
|
|
||||||
RunWebpack()
|
RunGulp()
|
||||||
{
|
{
|
||||||
ProgressStart 'Running webpack'
|
ProgressStart 'Running gulp'
|
||||||
yarn run build --env production
|
yarn run build --production
|
||||||
ProgressEnd 'Running webpack'
|
ProgressEnd 'Running gulp'
|
||||||
}
|
}
|
||||||
|
|
||||||
PackageFiles()
|
PackageFiles()
|
||||||
@@ -129,7 +118,7 @@ PackageLinux()
|
|||||||
|
|
||||||
echo "Adding Radarr.Mono to UpdatePackage"
|
echo "Adding Radarr.Mono to UpdatePackage"
|
||||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||||
if [ "$framework" = "net6.0" ]; then
|
if [ "$framework" = "netcoreapp3.1" ]; then
|
||||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||||
fi
|
fi
|
||||||
@@ -140,13 +129,17 @@ PackageLinux()
|
|||||||
PackageMacOS()
|
PackageMacOS()
|
||||||
{
|
{
|
||||||
local framework="$1"
|
local framework="$1"
|
||||||
local runtime="$2"
|
|
||||||
|
|
||||||
ProgressStart "Creating MacOS Package for $framework $runtime"
|
ProgressStart "Creating MacOS Package for $framework"
|
||||||
|
|
||||||
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
local folder=$artifactsFolder/macos/$framework/Radarr
|
||||||
|
|
||||||
PackageFiles "$folder" "$framework" "$runtime"
|
PackageFiles "$folder" "$framework" "osx-x64"
|
||||||
|
|
||||||
|
if [ "$framework" = "net462" ]; then
|
||||||
|
echo "Adding Startup script"
|
||||||
|
cp macOS/Radarr $folder
|
||||||
|
fi
|
||||||
|
|
||||||
echo "Removing Service helpers"
|
echo "Removing Service helpers"
|
||||||
rm -f $folder/ServiceUninstall.*
|
rm -f $folder/ServiceUninstall.*
|
||||||
@@ -157,7 +150,7 @@ PackageMacOS()
|
|||||||
|
|
||||||
echo "Adding Radarr.Mono to UpdatePackage"
|
echo "Adding Radarr.Mono to UpdatePackage"
|
||||||
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
cp $folder/Radarr.Mono.* $folder/Radarr.Update
|
||||||
if [ "$framework" = "net6.0" ]; then
|
if [ "$framework" = "netcoreapp3.1" ]; then
|
||||||
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
cp $folder/Mono.Posix.NETStandard.* $folder/Radarr.Update
|
||||||
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
cp $folder/libMonoPosixHelper.* $folder/Radarr.Update
|
||||||
fi
|
fi
|
||||||
@@ -168,11 +161,10 @@ PackageMacOS()
|
|||||||
PackageMacOSApp()
|
PackageMacOSApp()
|
||||||
{
|
{
|
||||||
local framework="$1"
|
local framework="$1"
|
||||||
local runtime="$2"
|
|
||||||
|
|
||||||
ProgressStart "Creating macOS App Package for $framework $runtime"
|
ProgressStart "Creating macOS App Package for $framework"
|
||||||
|
|
||||||
local folder="$artifactsFolder/$runtime-app/$framework"
|
local folder=$artifactsFolder/macos-app/$framework
|
||||||
|
|
||||||
rm -rf $folder
|
rm -rf $folder
|
||||||
mkdir -p $folder
|
mkdir -p $folder
|
||||||
@@ -180,7 +172,7 @@ PackageMacOSApp()
|
|||||||
mkdir -p $folder/Radarr.app/Contents/MacOS
|
mkdir -p $folder/Radarr.app/Contents/MacOS
|
||||||
|
|
||||||
echo "Copying Binaries"
|
echo "Copying Binaries"
|
||||||
cp -r $artifactsFolder/$runtime/$framework/Radarr/* $folder/Radarr.app/Contents/MacOS
|
cp -r $artifactsFolder/macos/$framework/Radarr/* $folder/Radarr.app/Contents/MacOS
|
||||||
|
|
||||||
echo "Removing Update Folder"
|
echo "Removing Update Folder"
|
||||||
rm -r $folder/Radarr.app/Contents/MacOS/Radarr.Update
|
rm -r $folder/Radarr.app/Contents/MacOS/Radarr.Update
|
||||||
@@ -198,7 +190,6 @@ PackageWindows()
|
|||||||
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
local folder=$artifactsFolder/$runtime/$framework/Radarr
|
||||||
|
|
||||||
PackageFiles "$folder" "$framework" "$runtime"
|
PackageFiles "$folder" "$framework" "$runtime"
|
||||||
cp -r $outputFolder/$framework-windows/$runtime/publish/* $folder
|
|
||||||
|
|
||||||
echo "Removing Radarr.Mono"
|
echo "Removing Radarr.Mono"
|
||||||
rm -f $folder/Radarr.Mono.*
|
rm -f $folder/Radarr.Mono.*
|
||||||
@@ -220,15 +211,15 @@ Package()
|
|||||||
IFS='-' read -ra SPLIT <<< "$runtime"
|
IFS='-' read -ra SPLIT <<< "$runtime"
|
||||||
|
|
||||||
case "${SPLIT[0]}" in
|
case "${SPLIT[0]}" in
|
||||||
linux|freebsd*)
|
linux)
|
||||||
PackageLinux "$framework" "$runtime"
|
PackageLinux "$framework" "$runtime"
|
||||||
;;
|
;;
|
||||||
win)
|
win)
|
||||||
PackageWindows "$framework" "$runtime"
|
PackageWindows "$framework" "$runtime"
|
||||||
;;
|
;;
|
||||||
osx)
|
osx)
|
||||||
PackageMacOS "$framework" "$runtime"
|
PackageMacOS "$framework"
|
||||||
PackageMacOSApp "$framework" "$runtime"
|
PackageMacOSApp "$framework"
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
}
|
}
|
||||||
@@ -265,7 +256,6 @@ if [ $# -eq 0 ]; then
|
|||||||
FRONTEND=YES
|
FRONTEND=YES
|
||||||
PACKAGES=YES
|
PACKAGES=YES
|
||||||
LINT=YES
|
LINT=YES
|
||||||
ENABLE_BSD=NO
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
while [[ $# -gt 0 ]]
|
while [[ $# -gt 0 ]]
|
||||||
@@ -277,10 +267,6 @@ case $key in
|
|||||||
BACKEND=YES
|
BACKEND=YES
|
||||||
shift # past argument
|
shift # past argument
|
||||||
;;
|
;;
|
||||||
--enable-bsd)
|
|
||||||
ENABLE_BSD=YES
|
|
||||||
shift # past argument
|
|
||||||
;;
|
|
||||||
-r|--runtime)
|
-r|--runtime)
|
||||||
RID="$2"
|
RID="$2"
|
||||||
shift # past argument
|
shift # past argument
|
||||||
@@ -321,22 +307,15 @@ set -- "${POSITIONAL[@]}" # restore positional parameters
|
|||||||
if [ "$BACKEND" = "YES" ];
|
if [ "$BACKEND" = "YES" ];
|
||||||
then
|
then
|
||||||
UpdateVersionNumber
|
UpdateVersionNumber
|
||||||
if [ "$ENABLE_BSD" = "YES" ];
|
|
||||||
then
|
|
||||||
EnableBsdSupport
|
|
||||||
fi
|
|
||||||
Build
|
Build
|
||||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||||
then
|
then
|
||||||
PackageTests "net6.0" "win-x64"
|
PackageTests "netcoreapp3.1" "win-x64"
|
||||||
PackageTests "net6.0" "win-x86"
|
PackageTests "netcoreapp3.1" "win-x86"
|
||||||
PackageTests "net6.0" "linux-x64"
|
PackageTests "netcoreapp3.1" "linux-x64"
|
||||||
PackageTests "net6.0" "linux-musl-x64"
|
PackageTests "netcoreapp3.1" "linux-musl-x64"
|
||||||
PackageTests "net6.0" "osx-x64"
|
PackageTests "netcoreapp3.1" "osx-x64"
|
||||||
if [ "$ENABLE_BSD" = "YES" ];
|
PackageTests "net462" "linux-x64"
|
||||||
then
|
|
||||||
PackageTests "net6.0" "freebsd-x64"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
PackageTests "$FRAMEWORK" "$RID"
|
PackageTests "$FRAMEWORK" "$RID"
|
||||||
fi
|
fi
|
||||||
@@ -345,7 +324,7 @@ fi
|
|||||||
if [ "$FRONTEND" = "YES" ];
|
if [ "$FRONTEND" = "YES" ];
|
||||||
then
|
then
|
||||||
YarnInstall
|
YarnInstall
|
||||||
RunWebpack
|
RunGulp
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$LINT" = "YES" ];
|
if [ "$LINT" = "YES" ];
|
||||||
@@ -364,20 +343,15 @@ then
|
|||||||
|
|
||||||
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
|
||||||
then
|
then
|
||||||
Package "net6.0" "win-x64"
|
Package "netcoreapp3.1" "win-x64"
|
||||||
Package "net6.0" "win-x86"
|
Package "netcoreapp3.1" "win-x86"
|
||||||
Package "net6.0" "linux-x64"
|
Package "netcoreapp3.1" "linux-x64"
|
||||||
Package "net6.0" "linux-musl-x64"
|
Package "netcoreapp3.1" "linux-musl-x64"
|
||||||
Package "net6.0" "linux-arm64"
|
Package "netcoreapp3.1" "linux-arm64"
|
||||||
Package "net6.0" "linux-musl-arm64"
|
Package "netcoreapp3.1" "linux-musl-arm64"
|
||||||
Package "net6.0" "linux-arm"
|
Package "netcoreapp3.1" "linux-arm"
|
||||||
Package "net6.0" "linux-musl-arm"
|
Package "netcoreapp3.1" "osx-x64"
|
||||||
Package "net6.0" "osx-x64"
|
Package "net462" "linux-x64"
|
||||||
Package "net6.0" "osx-arm64"
|
|
||||||
if [ "$ENABLE_BSD" = "YES" ];
|
|
||||||
then
|
|
||||||
Package "net6.0" "freebsd-x64"
|
|
||||||
fi
|
|
||||||
else
|
else
|
||||||
Package "$FRAMEWORK" "$RID"
|
Package "$FRAMEWORK" "$RID"
|
||||||
fi
|
fi
|
||||||
|
|||||||
@@ -6,10 +6,8 @@ const dirs = fs
|
|||||||
.map((dirent) => dirent.name)
|
.map((dirent) => dirent.name)
|
||||||
.join('|');
|
.join('|');
|
||||||
|
|
||||||
const frontendFolder = __dirname;
|
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
parser: '@babel/eslint-parser',
|
parser: 'babel-eslint',
|
||||||
|
|
||||||
env: {
|
env: {
|
||||||
browser: true,
|
browser: true,
|
||||||
@@ -27,9 +25,6 @@ module.exports = {
|
|||||||
parserOptions: {
|
parserOptions: {
|
||||||
ecmaVersion: 6,
|
ecmaVersion: 6,
|
||||||
sourceType: 'module',
|
sourceType: 'module',
|
||||||
babelOptions: {
|
|
||||||
configFile: `${frontendFolder}/babel.config.js`
|
|
||||||
},
|
|
||||||
ecmaFeatures: {
|
ecmaFeatures: {
|
||||||
modules: true,
|
modules: true,
|
||||||
impliedStrict: true
|
impliedStrict: true
|
||||||
@@ -276,7 +271,7 @@ module.exports = {
|
|||||||
|
|
||||||
// ImportSort
|
// ImportSort
|
||||||
|
|
||||||
'simple-import-sort/imports': 'error',
|
'simple-import-sort/sort': 'error',
|
||||||
'import/newline-after-import': 'error',
|
'import/newline-after-import': 'error',
|
||||||
|
|
||||||
// React
|
// React
|
||||||
@@ -314,7 +309,7 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
files: ['*.js'],
|
files: ['*.js'],
|
||||||
rules: {
|
rules: {
|
||||||
'simple-import-sort/imports': [
|
'simple-import-sort/sort': [
|
||||||
'error',
|
'error',
|
||||||
{
|
{
|
||||||
groups: [
|
groups: [
|
||||||
|
|||||||
@@ -1,270 +0,0 @@
|
|||||||
const path = require('path');
|
|
||||||
const webpack = require('webpack');
|
|
||||||
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');
|
|
||||||
const TerserPlugin = require('terser-webpack-plugin');
|
|
||||||
|
|
||||||
module.exports = (env) => {
|
|
||||||
const uiFolder = 'UI';
|
|
||||||
const frontendFolder = path.join(__dirname, '..');
|
|
||||||
const srcFolder = path.join(frontendFolder, 'src');
|
|
||||||
const isProduction = !!env.production;
|
|
||||||
const isProfiling = isProduction && !!env.profile;
|
|
||||||
const inlineWebWorkers = 'no-fallback';
|
|
||||||
|
|
||||||
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
|
|
||||||
|
|
||||||
console.log('Source Folder:', srcFolder);
|
|
||||||
console.log('Output Folder:', distFolder);
|
|
||||||
console.log('isProduction:', isProduction);
|
|
||||||
console.log('isProfiling:', isProfiling);
|
|
||||||
|
|
||||||
const config = {
|
|
||||||
mode: isProduction ? 'production' : 'development',
|
|
||||||
devtool: isProduction ? 'source-map' : 'eval-source-map',
|
|
||||||
|
|
||||||
stats: {
|
|
||||||
children: false
|
|
||||||
},
|
|
||||||
|
|
||||||
watchOptions: {
|
|
||||||
ignored: /node_modules/
|
|
||||||
},
|
|
||||||
|
|
||||||
entry: {
|
|
||||||
index: 'index.js'
|
|
||||||
},
|
|
||||||
|
|
||||||
resolve: {
|
|
||||||
modules: [
|
|
||||||
srcFolder,
|
|
||||||
path.join(srcFolder, 'Shims'),
|
|
||||||
'node_modules'
|
|
||||||
],
|
|
||||||
alias: {
|
|
||||||
jquery: 'jquery/src/jquery'
|
|
||||||
},
|
|
||||||
fallback: {
|
|
||||||
buffer: false,
|
|
||||||
http: false,
|
|
||||||
https: false,
|
|
||||||
url: false,
|
|
||||||
util: false,
|
|
||||||
net: false
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
output: {
|
|
||||||
path: distFolder,
|
|
||||||
publicPath: '/',
|
|
||||||
filename: '[name].js',
|
|
||||||
sourceMapFilename: '[file].map'
|
|
||||||
},
|
|
||||||
|
|
||||||
optimization: {
|
|
||||||
moduleIds: 'deterministic',
|
|
||||||
chunkIds: 'named',
|
|
||||||
splitChunks: {
|
|
||||||
chunks: 'initial',
|
|
||||||
name: 'vendors'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
performance: {
|
|
||||||
hints: false
|
|
||||||
},
|
|
||||||
|
|
||||||
plugins: [
|
|
||||||
new webpack.DefinePlugin({
|
|
||||||
__DEV__: !isProduction,
|
|
||||||
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
|
||||||
}),
|
|
||||||
|
|
||||||
new MiniCssExtractPlugin({
|
|
||||||
filename: 'Content/styles.css'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new HtmlWebpackPlugin({
|
|
||||||
template: 'frontend/src/index.ejs',
|
|
||||||
filename: 'index.html',
|
|
||||||
publicPath: '/'
|
|
||||||
}),
|
|
||||||
|
|
||||||
new FileManagerPlugin({
|
|
||||||
events: {
|
|
||||||
onEnd: {
|
|
||||||
copy: [
|
|
||||||
// HTML
|
|
||||||
{
|
|
||||||
source: 'frontend/src/*.html',
|
|
||||||
destination: distFolder
|
|
||||||
},
|
|
||||||
|
|
||||||
// Fonts
|
|
||||||
{
|
|
||||||
source: 'frontend/src/Content/Fonts/*.*',
|
|
||||||
destination: path.join(distFolder, 'Content/Fonts')
|
|
||||||
},
|
|
||||||
|
|
||||||
// Icon Images
|
|
||||||
{
|
|
||||||
source: 'frontend/src/Content/Images/Icons/*.*',
|
|
||||||
destination: path.join(distFolder, 'Content/Images/Icons')
|
|
||||||
},
|
|
||||||
|
|
||||||
// Images
|
|
||||||
{
|
|
||||||
source: 'frontend/src/Content/Images/*.*',
|
|
||||||
destination: path.join(distFolder, 'Content/Images')
|
|
||||||
},
|
|
||||||
|
|
||||||
// Robots
|
|
||||||
{
|
|
||||||
source: 'frontend/src/Content/robots.txt',
|
|
||||||
destination: path.join(distFolder, 'Content/robots.txt')
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}),
|
|
||||||
|
|
||||||
new LiveReloadPlugin()
|
|
||||||
],
|
|
||||||
|
|
||||||
resolveLoader: {
|
|
||||||
modules: [
|
|
||||||
'node_modules',
|
|
||||||
'frontend/build/webpack/'
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
module: {
|
|
||||||
rules: [
|
|
||||||
{
|
|
||||||
test: /\.worker\.js$/,
|
|
||||||
use: {
|
|
||||||
loader: 'worker-loader',
|
|
||||||
options: {
|
|
||||||
filename: '[name].js',
|
|
||||||
inline: inlineWebWorkers
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
test: /\.js?$/,
|
|
||||||
exclude: /(node_modules|JsLibraries)/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'babel-loader',
|
|
||||||
options: {
|
|
||||||
configFile: `${frontendFolder}/babel.config.js`,
|
|
||||||
envName: isProduction ? 'production' : 'development',
|
|
||||||
presets: [
|
|
||||||
[
|
|
||||||
'@babel/preset-env',
|
|
||||||
{
|
|
||||||
modules: false,
|
|
||||||
loose: true,
|
|
||||||
debug: false,
|
|
||||||
useBuiltIns: 'entry',
|
|
||||||
corejs: 3
|
|
||||||
}
|
|
||||||
]
|
|
||||||
]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// CSS Modules
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
exclude: /(node_modules|globals.css)/,
|
|
||||||
use: [
|
|
||||||
{ loader: MiniCssExtractPlugin.loader },
|
|
||||||
{
|
|
||||||
loader: 'css-loader',
|
|
||||||
options: {
|
|
||||||
importLoaders: 1,
|
|
||||||
modules: {
|
|
||||||
localIdentName: '[name]/[local]/[hash:base64:5]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
loader: 'postcss-loader',
|
|
||||||
options: {
|
|
||||||
postcssOptions: {
|
|
||||||
config: 'frontend/postcss.config.js'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// Global styles
|
|
||||||
{
|
|
||||||
test: /\.css$/,
|
|
||||||
include: /(node_modules|globals.css)/,
|
|
||||||
use: [
|
|
||||||
'style-loader',
|
|
||||||
{
|
|
||||||
loader: 'css-loader'
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
// Fonts
|
|
||||||
{
|
|
||||||
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'url-loader',
|
|
||||||
options: {
|
|
||||||
limit: 10240,
|
|
||||||
mimetype: 'application/font-woff',
|
|
||||||
emitFile: false,
|
|
||||||
name: 'Content/Fonts/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
{
|
|
||||||
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
|
||||||
use: [
|
|
||||||
{
|
|
||||||
loader: 'file-loader',
|
|
||||||
options: {
|
|
||||||
emitFile: false,
|
|
||||||
name: 'Content/Fonts/[name].[ext]'
|
|
||||||
}
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
if (isProfiling) {
|
|
||||||
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
|
|
||||||
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
|
||||||
|
|
||||||
config.optimization.minimizer = [
|
|
||||||
new TerserPlugin({
|
|
||||||
cache: true,
|
|
||||||
parallel: true,
|
|
||||||
sourceMap: true, // Must be set to true if using source-maps in production
|
|
||||||
terserOptions: {
|
|
||||||
mangle: false,
|
|
||||||
keep_classnames: true,
|
|
||||||
keep_fnames: true
|
|
||||||
}
|
|
||||||
})
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
return config;
|
|
||||||
};
|
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
|
||||||
|
require('./clean');
|
||||||
|
require('./copy');
|
||||||
|
require('./webpack');
|
||||||
|
|
||||||
|
gulp.task('build',
|
||||||
|
gulp.series('clean',
|
||||||
|
gulp.parallel(
|
||||||
|
'webpack',
|
||||||
|
'copyHtml',
|
||||||
|
'copyFonts',
|
||||||
|
'copyImages',
|
||||||
|
'copyRobots'
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const del = require('del');
|
||||||
|
|
||||||
|
const paths = require('./helpers/paths');
|
||||||
|
|
||||||
|
gulp.task('clean', () => {
|
||||||
|
return del([paths.dest.root]);
|
||||||
|
});
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
const path = require('path');
|
||||||
|
const gulp = require('gulp');
|
||||||
|
const print = require('gulp-print').default;
|
||||||
|
const cache = require('gulp-cached');
|
||||||
|
const livereload = require('gulp-livereload');
|
||||||
|
const paths = require('./helpers/paths.js');
|
||||||
|
|
||||||
|
gulp.task('copyHtml', () => {
|
||||||
|
return gulp.src(paths.src.html, { base: paths.src.root })
|
||||||
|
.pipe(cache('copyHtml'))
|
||||||
|
.pipe(print())
|
||||||
|
.pipe(gulp.dest(paths.dest.root))
|
||||||
|
.pipe(livereload());
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('copyFonts', () => {
|
||||||
|
return gulp.src(
|
||||||
|
path.join(paths.src.fonts, '**', '*.*'), { base: paths.src.root }
|
||||||
|
)
|
||||||
|
.pipe(cache('copyFonts'))
|
||||||
|
.pipe(print())
|
||||||
|
.pipe(gulp.dest(paths.dest.root))
|
||||||
|
.pipe(livereload());
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('copyImages', () => {
|
||||||
|
return gulp.src(
|
||||||
|
path.join(paths.src.images, '**', '*.*'), { base: paths.src.root }
|
||||||
|
)
|
||||||
|
.pipe(cache('copyImages'))
|
||||||
|
.pipe(print())
|
||||||
|
.pipe(gulp.dest(paths.dest.root))
|
||||||
|
.pipe(livereload());
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('copyRobots', () => {
|
||||||
|
return gulp.src(paths.src.robots, { base: paths.src.root })
|
||||||
|
.pipe(cache('copyRobots'))
|
||||||
|
.pipe(print())
|
||||||
|
.pipe(gulp.dest(paths.dest.root))
|
||||||
|
.pipe(livereload());
|
||||||
|
});
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
require('./build.js');
|
||||||
|
require('./clean.js');
|
||||||
|
require('./copy.js');
|
||||||
|
require('./watch.js');
|
||||||
|
require('./webpack.js');
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
const colors = require('ansi-colors');
|
||||||
|
|
||||||
|
module.exports = function errorHandler(error) {
|
||||||
|
console.log(colors.red(`Error (${error.plugin}): ${error.message}`));
|
||||||
|
this.emit('end');
|
||||||
|
};
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
const root = './frontend/src';
|
||||||
|
|
||||||
|
const paths = {
|
||||||
|
src: {
|
||||||
|
root,
|
||||||
|
html: `${root}/*.html`,
|
||||||
|
scripts: `${root}/**/*.js`,
|
||||||
|
content: `${root}/Content/`,
|
||||||
|
fonts: `${root}/Content/Fonts/`,
|
||||||
|
images: `${root}/Content/Images/`,
|
||||||
|
robots: `${root}/Content/robots.txt`,
|
||||||
|
exclude: {
|
||||||
|
libs: `!${root}/JsLibraries/**`
|
||||||
|
}
|
||||||
|
},
|
||||||
|
dest: {
|
||||||
|
root: './_output/UI/',
|
||||||
|
content: './_output/UI/Content/',
|
||||||
|
fonts: './_output/UI/Content/Fonts/',
|
||||||
|
images: './_output/UI/Content/Images/'
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = paths;
|
||||||
@@ -0,0 +1,19 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const livereload = require('gulp-livereload');
|
||||||
|
const gulpWatch = require('gulp-watch');
|
||||||
|
const paths = require('./helpers/paths.js');
|
||||||
|
|
||||||
|
require('./copy.js');
|
||||||
|
require('./webpack.js');
|
||||||
|
|
||||||
|
function watch() {
|
||||||
|
livereload.listen({ start: true });
|
||||||
|
|
||||||
|
gulp.task('webpackWatch')();
|
||||||
|
gulpWatch(paths.src.html, gulp.series('copyHtml'));
|
||||||
|
gulpWatch(`${paths.src.fonts}**/*.*`, gulp.series('copyFonts'));
|
||||||
|
gulpWatch(`${paths.src.images}**/*.*`, gulp.series('copyImages'));
|
||||||
|
gulpWatch(paths.src.robots, gulp.series('copyRobots'));
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('watch', gulp.series('build', watch));
|
||||||
@@ -0,0 +1,271 @@
|
|||||||
|
const gulp = require('gulp');
|
||||||
|
const webpackStream = require('webpack-stream');
|
||||||
|
const livereload = require('gulp-livereload');
|
||||||
|
const path = require('path');
|
||||||
|
const webpack = require('webpack');
|
||||||
|
const errorHandler = require('./helpers/errorHandler');
|
||||||
|
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin');
|
||||||
|
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
|
||||||
|
const HtmlWebpackPlugin = require('html-webpack-plugin');
|
||||||
|
const HtmlWebpackPluginHtmlTags = require('html-webpack-plugin/lib/html-tags');
|
||||||
|
const TerserPlugin = require('terser-webpack-plugin');
|
||||||
|
|
||||||
|
const uiFolder = 'UI';
|
||||||
|
const frontendFolder = path.join(__dirname, '..');
|
||||||
|
const srcFolder = path.join(frontendFolder, 'src');
|
||||||
|
const isProduction = process.argv.indexOf('--production') > -1;
|
||||||
|
const isProfiling = isProduction && process.argv.indexOf('--profile') > -1;
|
||||||
|
const inlineWebWorkers = 'no-fallback';
|
||||||
|
|
||||||
|
const distFolder = path.resolve(frontendFolder, '..', '_output', uiFolder);
|
||||||
|
|
||||||
|
console.log('Source Folder:', srcFolder);
|
||||||
|
console.log('Output Folder:', distFolder);
|
||||||
|
console.log('isProduction:', isProduction);
|
||||||
|
console.log('isProfiling:', isProfiling);
|
||||||
|
|
||||||
|
const cssVarsFiles = [
|
||||||
|
'../src/Styles/Variables/colors',
|
||||||
|
'../src/Styles/Variables/dimensions',
|
||||||
|
'../src/Styles/Variables/fonts',
|
||||||
|
'../src/Styles/Variables/animations',
|
||||||
|
'../src/Styles/Variables/zIndexes'
|
||||||
|
].map(require.resolve);
|
||||||
|
|
||||||
|
// Override the way HtmlWebpackPlugin injects the scripts
|
||||||
|
// TODO: Find a better way to get these paths without
|
||||||
|
HtmlWebpackPlugin.prototype.injectAssetsIntoHtml = function(html, assets, assetTags) {
|
||||||
|
const head = assetTags.headTags.map((v) => {
|
||||||
|
const href = v.attributes.href
|
||||||
|
.replace('\\', '/')
|
||||||
|
.replace('%5C', '/');
|
||||||
|
|
||||||
|
v.attributes = { rel: 'stylesheet', type: 'text/css', href: `/${href}` };
|
||||||
|
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
|
||||||
|
});
|
||||||
|
const body = assetTags.bodyTags.map((v) => {
|
||||||
|
v.attributes = { src: `/${v.attributes.src}` };
|
||||||
|
return HtmlWebpackPluginHtmlTags.htmlTagObjectToString(v, this.options.xhtml);
|
||||||
|
});
|
||||||
|
|
||||||
|
return html
|
||||||
|
.replace('<!-- webpack bundles head -->', head.join('\r\n '))
|
||||||
|
.replace('<!-- webpack bundles body -->', body.join('\r\n '));
|
||||||
|
};
|
||||||
|
|
||||||
|
const plugins = [
|
||||||
|
new OptimizeCssAssetsPlugin({}),
|
||||||
|
|
||||||
|
new webpack.DefinePlugin({
|
||||||
|
__DEV__: !isProduction,
|
||||||
|
'process.env.NODE_ENV': isProduction ? JSON.stringify('production') : JSON.stringify('development')
|
||||||
|
}),
|
||||||
|
|
||||||
|
new MiniCssExtractPlugin({
|
||||||
|
filename: path.join('Content', 'styles.css')
|
||||||
|
}),
|
||||||
|
|
||||||
|
new HtmlWebpackPlugin({
|
||||||
|
template: 'frontend/src/index.html',
|
||||||
|
filename: 'index.html'
|
||||||
|
})
|
||||||
|
];
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
mode: isProduction ? 'production' : 'development',
|
||||||
|
devtool: '#source-map',
|
||||||
|
|
||||||
|
stats: {
|
||||||
|
children: false
|
||||||
|
},
|
||||||
|
|
||||||
|
watchOptions: {
|
||||||
|
ignored: /node_modules/
|
||||||
|
},
|
||||||
|
|
||||||
|
entry: {
|
||||||
|
index: 'index.js'
|
||||||
|
},
|
||||||
|
|
||||||
|
resolve: {
|
||||||
|
modules: [
|
||||||
|
srcFolder,
|
||||||
|
path.join(srcFolder, 'Shims'),
|
||||||
|
'node_modules'
|
||||||
|
],
|
||||||
|
alias: {
|
||||||
|
jquery: 'jquery/src/jquery'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
output: {
|
||||||
|
path: distFolder,
|
||||||
|
filename: '[name].js',
|
||||||
|
sourceMapFilename: '[file].map'
|
||||||
|
},
|
||||||
|
|
||||||
|
optimization: {
|
||||||
|
chunkIds: 'named',
|
||||||
|
splitChunks: {
|
||||||
|
chunks: 'initial'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
performance: {
|
||||||
|
hints: false
|
||||||
|
},
|
||||||
|
|
||||||
|
plugins,
|
||||||
|
|
||||||
|
resolveLoader: {
|
||||||
|
modules: [
|
||||||
|
'node_modules',
|
||||||
|
'frontend/gulp/webpack/'
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
module: {
|
||||||
|
rules: [
|
||||||
|
{
|
||||||
|
test: /\.worker\.js$/,
|
||||||
|
use: {
|
||||||
|
loader: 'worker-loader',
|
||||||
|
options: {
|
||||||
|
filename: '[name].js',
|
||||||
|
inline: inlineWebWorkers
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
test: /\.js?$/,
|
||||||
|
exclude: /(node_modules|JsLibraries)/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'babel-loader',
|
||||||
|
options: {
|
||||||
|
configFile: `${frontendFolder}/babel.config.js`,
|
||||||
|
envName: isProduction ? 'production' : 'development',
|
||||||
|
presets: [
|
||||||
|
[
|
||||||
|
'@babel/preset-env',
|
||||||
|
{
|
||||||
|
modules: false,
|
||||||
|
loose: true,
|
||||||
|
debug: false,
|
||||||
|
useBuiltIns: 'entry',
|
||||||
|
corejs: 3
|
||||||
|
}
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// CSS Modules
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
exclude: /(node_modules|globals.css)/,
|
||||||
|
use: [
|
||||||
|
{ loader: MiniCssExtractPlugin.loader },
|
||||||
|
{
|
||||||
|
loader: 'css-loader',
|
||||||
|
options: {
|
||||||
|
importLoaders: 1,
|
||||||
|
modules: {
|
||||||
|
localIdentName: '[name]/[local]/[hash:base64:5]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
loader: 'postcss-loader',
|
||||||
|
options: {
|
||||||
|
ident: 'postcss',
|
||||||
|
config: {
|
||||||
|
ctx: {
|
||||||
|
cssVarsFiles
|
||||||
|
},
|
||||||
|
path: 'frontend/postcss.config.js'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Global styles
|
||||||
|
{
|
||||||
|
test: /\.css$/,
|
||||||
|
include: /(node_modules|globals.css)/,
|
||||||
|
use: [
|
||||||
|
'style-loader',
|
||||||
|
{
|
||||||
|
loader: 'css-loader'
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
// Fonts
|
||||||
|
{
|
||||||
|
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'url-loader',
|
||||||
|
options: {
|
||||||
|
limit: 10240,
|
||||||
|
mimetype: 'application/font-woff',
|
||||||
|
emitFile: false,
|
||||||
|
name: 'Content/Fonts/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
{
|
||||||
|
test: /\.(ttf|eot|eot?#iefix|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||||
|
use: [
|
||||||
|
{
|
||||||
|
loader: 'file-loader',
|
||||||
|
options: {
|
||||||
|
emitFile: false,
|
||||||
|
name: 'Content/Fonts/[name].[ext]'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if (isProfiling) {
|
||||||
|
config.resolve.alias['react-dom$'] = 'react-dom/profiling';
|
||||||
|
config.resolve.alias['scheduler/tracing'] = 'scheduler/tracing-profiling';
|
||||||
|
|
||||||
|
config.optimization.minimizer = [
|
||||||
|
new TerserPlugin({
|
||||||
|
cache: true,
|
||||||
|
parallel: true,
|
||||||
|
sourceMap: true, // Must be set to true if using source-maps in production
|
||||||
|
terserOptions: {
|
||||||
|
mangle: false,
|
||||||
|
keep_classnames: true,
|
||||||
|
keep_fnames: true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
gulp.task('webpack', () => {
|
||||||
|
return webpackStream(config)
|
||||||
|
.pipe(gulp.dest('_output/UI'));
|
||||||
|
});
|
||||||
|
|
||||||
|
gulp.task('webpackWatch', () => {
|
||||||
|
config.watch = true;
|
||||||
|
|
||||||
|
return webpackStream(config, webpack)
|
||||||
|
.on('error', errorHandler)
|
||||||
|
.pipe(gulp.dest('_output/UI'))
|
||||||
|
.on('error', errorHandler)
|
||||||
|
.pipe(livereload())
|
||||||
|
.on('error', errorHandler);
|
||||||
|
});
|
||||||
+20
-29
@@ -1,32 +1,23 @@
|
|||||||
const reload = require('require-nocache')(module);
|
const reload = require('require-nocache')(module);
|
||||||
|
|
||||||
const cssVarsFiles = [
|
module.exports = (ctx, configPath, options) => {
|
||||||
'./src/Styles/Variables/colors',
|
const config = {
|
||||||
'./src/Styles/Variables/dimensions',
|
plugins: {
|
||||||
'./src/Styles/Variables/fonts',
|
'postcss-mixins': {
|
||||||
'./src/Styles/Variables/animations',
|
mixinsDir: [
|
||||||
'./src/Styles/Variables/zIndexes'
|
'frontend/src/Styles/Mixins'
|
||||||
].map(require.resolve);
|
]
|
||||||
|
},
|
||||||
|
'postcss-simple-vars': {
|
||||||
|
variables: () =>
|
||||||
|
ctx.options.cssVarsFiles.reduce((acc, vars) => {
|
||||||
|
return Object.assign(acc, reload(vars));
|
||||||
|
}, {})
|
||||||
|
},
|
||||||
|
'postcss-color-function': {},
|
||||||
|
'postcss-nested': {}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const mixinsFiles = [
|
return config;
|
||||||
'frontend/src/Styles/Mixins/cover.css',
|
};
|
||||||
'frontend/src/Styles/Mixins/linkOverlay.css',
|
|
||||||
'frontend/src/Styles/Mixins/scroller.css',
|
|
||||||
'frontend/src/Styles/Mixins/truncate.css'
|
|
||||||
];
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
plugins: [
|
|
||||||
['postcss-mixins', {
|
|
||||||
mixinsFiles
|
|
||||||
}],
|
|
||||||
['postcss-simple-vars', {
|
|
||||||
variables: () =>
|
|
||||||
cssVarsFiles.reduce((acc, vars) => {
|
|
||||||
return Object.assign(acc, reload(vars));
|
|
||||||
}, {})
|
|
||||||
}],
|
|
||||||
'postcss-color-function',
|
|
||||||
'postcss-nested'
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|||||||
+15
-15
@@ -19,9 +19,9 @@ import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
|||||||
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
import removeOldSelectedState from 'Utilities/Table/removeOldSelectedState';
|
||||||
import selectAll from 'Utilities/Table/selectAll';
|
import selectAll from 'Utilities/Table/selectAll';
|
||||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||||
import BlocklistRowConnector from './BlocklistRowConnector';
|
import BlacklistRowConnector from './BlacklistRowConnector';
|
||||||
|
|
||||||
class Blocklist extends Component {
|
class Blacklist extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -101,8 +101,8 @@ class Blocklist extends Component {
|
|||||||
columns,
|
columns,
|
||||||
totalRecords,
|
totalRecords,
|
||||||
isRemoving,
|
isRemoving,
|
||||||
isClearingBlocklistExecuting,
|
isClearingBlacklistExecuting,
|
||||||
onClearBlocklistPress,
|
onClearBlacklistPress,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -116,11 +116,11 @@ class Blocklist extends Component {
|
|||||||
const selectedIds = this.getSelectedIds();
|
const selectedIds = this.getSelectedIds();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title={translate('Blocklist')}>
|
<PageContent title={translate('Blacklist')}>
|
||||||
<PageToolbar>
|
<PageToolbar>
|
||||||
<PageToolbarSection>
|
<PageToolbarSection>
|
||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label={translate('RemoveSelected')}
|
label="Remove Selected"
|
||||||
iconName={icons.REMOVE}
|
iconName={icons.REMOVE}
|
||||||
isDisabled={!selectedIds.length}
|
isDisabled={!selectedIds.length}
|
||||||
isSpinning={isRemoving}
|
isSpinning={isRemoving}
|
||||||
@@ -130,8 +130,8 @@ class Blocklist extends Component {
|
|||||||
<PageToolbarButton
|
<PageToolbarButton
|
||||||
label={translate('Clear')}
|
label={translate('Clear')}
|
||||||
iconName={icons.CLEAR}
|
iconName={icons.CLEAR}
|
||||||
isSpinning={isClearingBlocklistExecuting}
|
isSpinning={isClearingBlacklistExecuting}
|
||||||
onPress={onClearBlocklistPress}
|
onPress={onClearBlacklistPress}
|
||||||
/>
|
/>
|
||||||
</PageToolbarSection>
|
</PageToolbarSection>
|
||||||
|
|
||||||
@@ -157,7 +157,7 @@ class Blocklist extends Component {
|
|||||||
{
|
{
|
||||||
!isFetching && !!error &&
|
!isFetching && !!error &&
|
||||||
<div>
|
<div>
|
||||||
{translate('UnableToLoadBlocklist')}
|
{translate('UnableToLoadBlacklist')}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -183,7 +183,7 @@ class Blocklist extends Component {
|
|||||||
{
|
{
|
||||||
items.map((item) => {
|
items.map((item) => {
|
||||||
return (
|
return (
|
||||||
<BlocklistRowConnector
|
<BlacklistRowConnector
|
||||||
key={item.id}
|
key={item.id}
|
||||||
isSelected={selectedState[item.id] || false}
|
isSelected={selectedState[item.id] || false}
|
||||||
columns={columns}
|
columns={columns}
|
||||||
@@ -209,7 +209,7 @@ class Blocklist extends Component {
|
|||||||
isOpen={isConfirmRemoveModalOpen}
|
isOpen={isConfirmRemoveModalOpen}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
title={translate('RemoveSelected')}
|
title={translate('RemoveSelected')}
|
||||||
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist')}
|
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlacklist')}
|
||||||
confirmLabel={translate('RemoveSelected')}
|
confirmLabel={translate('RemoveSelected')}
|
||||||
onConfirm={this.onRemoveSelectedConfirmed}
|
onConfirm={this.onRemoveSelectedConfirmed}
|
||||||
onCancel={this.onConfirmRemoveModalClose}
|
onCancel={this.onConfirmRemoveModalClose}
|
||||||
@@ -219,7 +219,7 @@ class Blocklist extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Blocklist.propTypes = {
|
Blacklist.propTypes = {
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
@@ -227,9 +227,9 @@ Blocklist.propTypes = {
|
|||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
totalRecords: PropTypes.number,
|
totalRecords: PropTypes.number,
|
||||||
isRemoving: PropTypes.bool.isRequired,
|
isRemoving: PropTypes.bool.isRequired,
|
||||||
isClearingBlocklistExecuting: PropTypes.bool.isRequired,
|
isClearingBlacklistExecuting: PropTypes.bool.isRequired,
|
||||||
onRemoveSelected: PropTypes.func.isRequired,
|
onRemoveSelected: PropTypes.func.isRequired,
|
||||||
onClearBlocklistPress: PropTypes.func.isRequired
|
onClearBlacklistPress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Blocklist;
|
export default Blacklist;
|
||||||
@@ -0,0 +1,160 @@
|
|||||||
|
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)
|
||||||
|
);
|
||||||
+3
-3
@@ -10,7 +10,7 @@ import ModalFooter from 'Components/Modal/ModalFooter';
|
|||||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
|
|
||||||
class BlocklistDetailsModal extends Component {
|
class BlacklistDetailsModal extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Render
|
// Render
|
||||||
@@ -78,7 +78,7 @@ class BlocklistDetailsModal extends Component {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BlocklistDetailsModal.propTypes = {
|
BlacklistDetailsModal.propTypes = {
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
sourceTitle: PropTypes.string.isRequired,
|
sourceTitle: PropTypes.string.isRequired,
|
||||||
protocol: PropTypes.string.isRequired,
|
protocol: PropTypes.string.isRequired,
|
||||||
@@ -87,4 +87,4 @@ BlocklistDetailsModal.propTypes = {
|
|||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BlocklistDetailsModal;
|
export default BlacklistDetailsModal;
|
||||||
+7
-7
@@ -11,10 +11,10 @@ import MovieLanguage from 'Movie/MovieLanguage';
|
|||||||
import MovieQuality from 'Movie/MovieQuality';
|
import MovieQuality from 'Movie/MovieQuality';
|
||||||
import MovieTitleLink from 'Movie/MovieTitleLink';
|
import MovieTitleLink from 'Movie/MovieTitleLink';
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import BlocklistDetailsModal from './BlocklistDetailsModal';
|
import BlacklistDetailsModal from './BlacklistDetailsModal';
|
||||||
import styles from './BlocklistRow.css';
|
import styles from './BlacklistRow.css';
|
||||||
|
|
||||||
class BlocklistRow extends Component {
|
class BlacklistRow extends Component {
|
||||||
|
|
||||||
//
|
//
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
@@ -166,7 +166,7 @@ class BlocklistRow extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton
|
<IconButton
|
||||||
title={translate('RemoveFromBlocklist')}
|
title={translate('RemoveFromBlacklist')}
|
||||||
name={icons.REMOVE}
|
name={icons.REMOVE}
|
||||||
kind={kinds.DANGER}
|
kind={kinds.DANGER}
|
||||||
onPress={onRemovePress}
|
onPress={onRemovePress}
|
||||||
@@ -179,7 +179,7 @@ class BlocklistRow extends Component {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
<BlocklistDetailsModal
|
<BlacklistDetailsModal
|
||||||
isOpen={this.state.isDetailsModalOpen}
|
isOpen={this.state.isDetailsModalOpen}
|
||||||
sourceTitle={sourceTitle}
|
sourceTitle={sourceTitle}
|
||||||
protocol={protocol}
|
protocol={protocol}
|
||||||
@@ -193,7 +193,7 @@ class BlocklistRow extends Component {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
BlocklistRow.propTypes = {
|
BlacklistRow.propTypes = {
|
||||||
id: PropTypes.number.isRequired,
|
id: PropTypes.number.isRequired,
|
||||||
movie: PropTypes.object.isRequired,
|
movie: PropTypes.object.isRequired,
|
||||||
sourceTitle: PropTypes.string.isRequired,
|
sourceTitle: PropTypes.string.isRequired,
|
||||||
@@ -210,4 +210,4 @@ BlocklistRow.propTypes = {
|
|||||||
onRemovePress: PropTypes.func.isRequired
|
onRemovePress: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
export default BlocklistRow;
|
export default BlacklistRow;
|
||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { removeBlocklistItem } from 'Store/Actions/blocklistActions';
|
import { removeBlacklistItem } from 'Store/Actions/blacklistActions';
|
||||||
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
||||||
import BlocklistRow from './BlocklistRow';
|
import BlacklistRow from './BlacklistRow';
|
||||||
|
|
||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
@@ -18,9 +18,9 @@ function createMapStateToProps() {
|
|||||||
function createMapDispatchToProps(dispatch, props) {
|
function createMapDispatchToProps(dispatch, props) {
|
||||||
return {
|
return {
|
||||||
onRemovePress() {
|
onRemovePress() {
|
||||||
dispatch(removeBlocklistItem({ id: props.id }));
|
dispatch(removeBlacklistItem({ id: props.id }));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export default connect(createMapStateToProps, createMapDispatchToProps)(BlocklistRow);
|
export default connect(createMapStateToProps, createMapDispatchToProps)(BlacklistRow);
|
||||||
@@ -1,152 +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 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)
|
|
||||||
);
|
|
||||||
@@ -25,7 +25,6 @@ function HistoryDetails(props) {
|
|||||||
releaseGroup,
|
releaseGroup,
|
||||||
nzbInfoUrl,
|
nzbInfoUrl,
|
||||||
downloadClient,
|
downloadClient,
|
||||||
downloadClientName,
|
|
||||||
downloadId,
|
downloadId,
|
||||||
age,
|
age,
|
||||||
ageHours,
|
ageHours,
|
||||||
@@ -33,8 +32,6 @@ function HistoryDetails(props) {
|
|||||||
publishedDate
|
publishedDate
|
||||||
} = data;
|
} = data;
|
||||||
|
|
||||||
const downloadClientNameInfo = downloadClientName ?? downloadClient;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DescriptionList>
|
<DescriptionList>
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
@@ -74,12 +71,11 @@ function HistoryDetails(props) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
downloadClientNameInfo ?
|
!!downloadClient &&
|
||||||
<DescriptionListItem
|
<DescriptionListItem
|
||||||
title={translate('DownloadClient')}
|
title={translate('DownloadClient')}
|
||||||
data={downloadClientNameInfo}
|
data={downloadClient}
|
||||||
/> :
|
/>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -32,8 +32,6 @@ class Queue extends Component {
|
|||||||
constructor(props, context) {
|
constructor(props, context) {
|
||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this._shouldBlockRefresh = false;
|
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
allSelected: false,
|
allSelected: false,
|
||||||
allUnselected: false,
|
allUnselected: false,
|
||||||
@@ -45,14 +43,6 @@ class Queue extends Component {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
shouldComponentUpdate() {
|
|
||||||
if (this._shouldBlockRefresh) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
@@ -95,10 +85,6 @@ class Queue extends Component {
|
|||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onQueueRowModalOpenOrClose = (isOpen) => {
|
|
||||||
this._shouldBlockRefresh = isOpen;
|
|
||||||
}
|
|
||||||
|
|
||||||
onSelectAllChange = ({ value }) => {
|
onSelectAllChange = ({ value }) => {
|
||||||
this.setState(selectAll(this.state.selectedState, value));
|
this.setState(selectAll(this.state.selectedState, value));
|
||||||
}
|
}
|
||||||
@@ -114,19 +100,15 @@ class Queue extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
onRemoveSelectedPress = () => {
|
onRemoveSelectedPress = () => {
|
||||||
this.setState({ isConfirmRemoveModalOpen: true }, () => {
|
this.setState({ isConfirmRemoveModalOpen: true });
|
||||||
this._shouldBlockRefresh = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveSelectedConfirmed = (payload) => {
|
onRemoveSelectedConfirmed = (payload) => {
|
||||||
this._shouldBlockRefresh = false;
|
|
||||||
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
|
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
|
||||||
this.setState({ isConfirmRemoveModalOpen: false });
|
this.setState({ isConfirmRemoveModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onConfirmRemoveModalClose = () => {
|
onConfirmRemoveModalClose = () => {
|
||||||
this._shouldBlockRefresh = false;
|
|
||||||
this.setState({ isConfirmRemoveModalOpen: false });
|
this.setState({ isConfirmRemoveModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -226,7 +208,7 @@ class Queue extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
isAllPopulated && !hasError && !items.length &&
|
isPopulated && !hasError && !items.length &&
|
||||||
<div>
|
<div>
|
||||||
{translate('QueueIsEmpty')}
|
{translate('QueueIsEmpty')}
|
||||||
</div>
|
</div>
|
||||||
@@ -255,7 +237,6 @@ class Queue extends Component {
|
|||||||
columns={columns}
|
columns={columns}
|
||||||
{...item}
|
{...item}
|
||||||
onSelectedChange={this.onSelectedChange}
|
onSelectedChange={this.onSelectedChange}
|
||||||
onQueueRowModalOpenOrClose={this.onQueueRowModalOpenOrClose}
|
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
@@ -282,17 +263,6 @@ class Queue extends Component {
|
|||||||
return !!(item && item.movieId);
|
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}
|
onRemovePress={this.onRemoveSelectedConfirmed}
|
||||||
onModalClose={this.onConfirmRemoveModalClose}
|
onModalClose={this.onConfirmRemoveModalClose}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ class QueueConnector extends Component {
|
|||||||
const {
|
const {
|
||||||
useCurrentPage,
|
useCurrentPage,
|
||||||
fetchQueue,
|
fetchQueue,
|
||||||
fetchQueueStatus,
|
|
||||||
gotoQueueFirstPage
|
gotoQueueFirstPage
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
@@ -54,8 +53,6 @@ class QueueConnector extends Component {
|
|||||||
} else {
|
} else {
|
||||||
gotoQueueFirstPage();
|
gotoQueueFirstPage();
|
||||||
}
|
}
|
||||||
|
|
||||||
fetchQueueStatus();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentDidUpdate(prevProps) {
|
componentDidUpdate(prevProps) {
|
||||||
@@ -155,7 +152,6 @@ QueueConnector.propTypes = {
|
|||||||
useCurrentPage: PropTypes.bool.isRequired,
|
useCurrentPage: PropTypes.bool.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
fetchQueue: PropTypes.func.isRequired,
|
fetchQueue: PropTypes.func.isRequired,
|
||||||
fetchQueueStatus: PropTypes.func.isRequired,
|
|
||||||
gotoQueueFirstPage: PropTypes.func.isRequired,
|
gotoQueueFirstPage: PropTypes.func.isRequired,
|
||||||
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
gotoQueuePreviousPage: PropTypes.func.isRequired,
|
||||||
gotoQueueNextPage: PropTypes.func.isRequired,
|
gotoQueueNextPage: PropTypes.func.isRequired,
|
||||||
|
|||||||
@@ -42,33 +42,20 @@ class QueueRow extends Component {
|
|||||||
this.setState({ isRemoveQueueItemModalOpen: true });
|
this.setState({ isRemoveQueueItemModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveQueueItemModalConfirmed = (blocklist) => {
|
onRemoveQueueItemModalConfirmed = (blacklist) => {
|
||||||
const {
|
this.props.onRemoveQueueItemPress(blacklist);
|
||||||
onRemoveQueueItemPress,
|
|
||||||
onQueueRowModalOpenOrClose
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
onQueueRowModalOpenOrClose(false);
|
|
||||||
onRemoveQueueItemPress(blocklist);
|
|
||||||
|
|
||||||
this.setState({ isRemoveQueueItemModalOpen: false });
|
this.setState({ isRemoveQueueItemModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveQueueItemModalClose = () => {
|
onRemoveQueueItemModalClose = () => {
|
||||||
this.props.onQueueRowModalOpenOrClose(false);
|
|
||||||
|
|
||||||
this.setState({ isRemoveQueueItemModalOpen: false });
|
this.setState({ isRemoveQueueItemModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
onInteractiveImportPress = () => {
|
onInteractiveImportPress = () => {
|
||||||
this.props.onQueueRowModalOpenOrClose(true);
|
|
||||||
|
|
||||||
this.setState({ isInteractiveImportModalOpen: true });
|
this.setState({ isInteractiveImportModalOpen: true });
|
||||||
}
|
}
|
||||||
|
|
||||||
onInteractiveImportModalClose = () => {
|
onInteractiveImportModalClose = () => {
|
||||||
this.props.onQueueRowModalOpenOrClose(false);
|
|
||||||
|
|
||||||
this.setState({ isInteractiveImportModalOpen: false });
|
this.setState({ isInteractiveImportModalOpen: false });
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -332,7 +319,6 @@ class QueueRow extends Component {
|
|||||||
isOpen={isRemoveQueueItemModalOpen}
|
isOpen={isRemoveQueueItemModalOpen}
|
||||||
sourceTitle={title}
|
sourceTitle={title}
|
||||||
canIgnore={!!movie}
|
canIgnore={!!movie}
|
||||||
isPending={isPending}
|
|
||||||
onRemovePress={this.onRemoveQueueItemModalConfirmed}
|
onRemovePress={this.onRemoveQueueItemModalConfirmed}
|
||||||
onModalClose={this.onRemoveQueueItemModalClose}
|
onModalClose={this.onRemoveQueueItemModalClose}
|
||||||
/>
|
/>
|
||||||
@@ -373,8 +359,7 @@ QueueRow.propTypes = {
|
|||||||
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
columns: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onSelectedChange: PropTypes.func.isRequired,
|
onSelectedChange: PropTypes.func.isRequired,
|
||||||
onGrabPress: PropTypes.func.isRequired,
|
onGrabPress: PropTypes.func.isRequired,
|
||||||
onRemoveQueueItemPress: PropTypes.func.isRequired,
|
onRemoveQueueItemPress: PropTypes.func.isRequired
|
||||||
onQueueRowModalOpenOrClose: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
QueueRow.defaultProps = {
|
QueueRow.defaultProps = {
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ class RemoveQueueItemModal extends Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
remove: true,
|
remove: true,
|
||||||
blocklist: false
|
blacklist: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -32,7 +32,7 @@ class RemoveQueueItemModal extends Component {
|
|||||||
resetState = function() {
|
resetState = function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
remove: true,
|
remove: true,
|
||||||
blocklist: false
|
blacklist: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,8 +43,8 @@ class RemoveQueueItemModal extends Component {
|
|||||||
this.setState({ remove: value });
|
this.setState({ remove: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlocklistChange = ({ value }) => {
|
onBlacklistChange = ({ value }) => {
|
||||||
this.setState({ blocklist: value });
|
this.setState({ blacklist: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveConfirmed = () => {
|
onRemoveConfirmed = () => {
|
||||||
@@ -66,11 +66,10 @@ class RemoveQueueItemModal extends Component {
|
|||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
sourceTitle,
|
sourceTitle,
|
||||||
canIgnore,
|
canIgnore
|
||||||
isPending
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { remove, blocklist } = this.state;
|
const { remove, blacklist } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -90,31 +89,27 @@ class RemoveQueueItemModal extends Component {
|
|||||||
{translate('RemoveFromQueueText', [sourceTitle])}
|
{translate('RemoveFromQueueText', [sourceTitle])}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
|
||||||
isPending ?
|
|
||||||
null :
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
|
||||||
type={inputTypes.CHECK}
|
|
||||||
name="remove"
|
|
||||||
value={remove}
|
|
||||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
|
||||||
isDisabled={!canIgnore}
|
|
||||||
onChange={this.onRemoveChange}
|
|
||||||
/>
|
|
||||||
</FormGroup>
|
|
||||||
}
|
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>{translate('BlocklistRelease')}</FormLabel>
|
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="blocklist"
|
name="remove"
|
||||||
value={blocklist}
|
value={remove}
|
||||||
helpText={translate('BlocklistHelpText')}
|
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||||
onChange={this.onBlocklistChange}
|
isDisabled={!canIgnore}
|
||||||
|
onChange={this.onRemoveChange}
|
||||||
|
/>
|
||||||
|
</FormGroup>
|
||||||
|
|
||||||
|
<FormGroup>
|
||||||
|
<FormLabel>{translate('BlacklistRelease')}</FormLabel>
|
||||||
|
<FormInputGroup
|
||||||
|
type={inputTypes.CHECK}
|
||||||
|
name="blacklist"
|
||||||
|
value={blacklist}
|
||||||
|
helpText={translate('BlacklistHelpText')}
|
||||||
|
onChange={this.onBlacklistChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
@@ -142,7 +137,6 @@ RemoveQueueItemModal.propTypes = {
|
|||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
sourceTitle: PropTypes.string.isRequired,
|
sourceTitle: PropTypes.string.isRequired,
|
||||||
canIgnore: PropTypes.bool.isRequired,
|
canIgnore: PropTypes.bool.isRequired,
|
||||||
isPending: PropTypes.bool.isRequired,
|
|
||||||
onRemovePress: PropTypes.func.isRequired,
|
onRemovePress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
remove: true,
|
remove: true,
|
||||||
blocklist: false
|
blacklist: false
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -33,7 +33,7 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
resetState = function() {
|
resetState = function() {
|
||||||
this.setState({
|
this.setState({
|
||||||
remove: true,
|
remove: true,
|
||||||
blocklist: false
|
blacklist: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -44,8 +44,8 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
this.setState({ remove: value });
|
this.setState({ remove: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onBlocklistChange = ({ value }) => {
|
onBlacklistChange = ({ value }) => {
|
||||||
this.setState({ blocklist: value });
|
this.setState({ blacklist: value });
|
||||||
}
|
}
|
||||||
|
|
||||||
onRemoveConfirmed = () => {
|
onRemoveConfirmed = () => {
|
||||||
@@ -67,11 +67,10 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
const {
|
const {
|
||||||
isOpen,
|
isOpen,
|
||||||
selectedCount,
|
selectedCount,
|
||||||
canIgnore,
|
canIgnore
|
||||||
allPending
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const { remove, blocklist } = this.state;
|
const { remove, blacklist } = this.state;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
@@ -83,42 +82,38 @@ class RemoveQueueItemsModal extends Component {
|
|||||||
onModalClose={this.onModalClose}
|
onModalClose={this.onModalClose}
|
||||||
>
|
>
|
||||||
<ModalHeader>
|
<ModalHeader>
|
||||||
{selectedCount > 1 ? translate('RemoveSelectedItems') : translate('RemoveSelectedItem')}
|
Remove Selected Item{selectedCount > 1 ? 's' : ''}
|
||||||
</ModalHeader>
|
</ModalHeader>
|
||||||
|
|
||||||
<ModalBody>
|
<ModalBody>
|
||||||
<div className={styles.message}>
|
<div className={styles.message}>
|
||||||
{selectedCount > 1 ? translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', selectedCount) : translate('AreYouSureYouWantToRemoveSelectedItemFromQueue')}
|
{translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', [selectedCount, selectedCount > 1 ? 's' : ''])}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
<FormGroup>
|
||||||
allPending ?
|
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
||||||
null :
|
|
||||||
<FormGroup>
|
|
||||||
<FormLabel>{translate('RemoveFromDownloadClient')}</FormLabel>
|
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="remove"
|
name="remove"
|
||||||
value={remove}
|
value={remove}
|
||||||
helpTextWarning={translate('RemoveHelpTextWarning')}
|
helpTextWarning={translate('RemoveHelpTextWarning')}
|
||||||
isDisabled={!canIgnore}
|
isDisabled={!canIgnore}
|
||||||
onChange={this.onRemoveChange}
|
onChange={this.onRemoveChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
}
|
|
||||||
|
|
||||||
<FormGroup>
|
<FormGroup>
|
||||||
<FormLabel>
|
<FormLabel>
|
||||||
{selectedCount > 1 ? translate('BlocklistReleases') : translate('BlocklistRelease')}
|
Blacklist Release{selectedCount > 1 ? 's' : ''}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
|
||||||
<FormInputGroup
|
<FormInputGroup
|
||||||
type={inputTypes.CHECK}
|
type={inputTypes.CHECK}
|
||||||
name="blocklist"
|
name="blacklist"
|
||||||
value={blocklist}
|
value={blacklist}
|
||||||
helpText={translate('BlocklistHelpText')}
|
helpText={translate('BlacklistHelpText')}
|
||||||
onChange={this.onBlocklistChange}
|
onChange={this.onBlacklistChange}
|
||||||
/>
|
/>
|
||||||
</FormGroup>
|
</FormGroup>
|
||||||
|
|
||||||
@@ -146,7 +141,6 @@ RemoveQueueItemsModal.propTypes = {
|
|||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
selectedCount: PropTypes.number.isRequired,
|
selectedCount: PropTypes.number.isRequired,
|
||||||
canIgnore: PropTypes.bool.isRequired,
|
canIgnore: PropTypes.bool.isRequired,
|
||||||
allPending: PropTypes.bool.isRequired,
|
|
||||||
onRemovePress: PropTypes.func.isRequired,
|
onRemovePress: PropTypes.func.isRequired,
|
||||||
onModalClose: PropTypes.func.isRequired
|
onModalClose: PropTypes.func.isRequired
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -81,8 +81,7 @@ class AddNewMovie extends Component {
|
|||||||
const {
|
const {
|
||||||
error,
|
error,
|
||||||
items,
|
items,
|
||||||
hasExistingMovies,
|
hasExistingMovies
|
||||||
colorImpairedMode
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const term = this.state.term;
|
const term = this.state.term;
|
||||||
@@ -103,7 +102,7 @@ class AddNewMovie extends Component {
|
|||||||
className={styles.searchInput}
|
className={styles.searchInput}
|
||||||
name="movieLookup"
|
name="movieLookup"
|
||||||
value={term}
|
value={term}
|
||||||
placeholder="e.g. The Dark Knight, tmdb:155, imdb:tt0468569"
|
placeholder="eg. The Dark Knight, tmdb:155, imdb:tt0468569"
|
||||||
autoFocus={true}
|
autoFocus={true}
|
||||||
onChange={this.onSearchInputChange}
|
onChange={this.onSearchInputChange}
|
||||||
/>
|
/>
|
||||||
@@ -142,7 +141,6 @@ class AddNewMovie extends Component {
|
|||||||
return (
|
return (
|
||||||
<AddNewMovieSearchResultConnector
|
<AddNewMovieSearchResultConnector
|
||||||
key={item.tmdbId}
|
key={item.tmdbId}
|
||||||
colorImpairedMode={colorImpairedMode}
|
|
||||||
{...item}
|
{...item}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
@@ -161,7 +159,7 @@ class AddNewMovie extends Component {
|
|||||||
{translate('YouCanAlsoSearch')}
|
{translate('YouCanAlsoSearch')}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<Link to="https://wiki.servarr.com/radarr/faq#why-can-i-not-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')}
|
{translate('CantFindMovie')}
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
@@ -215,8 +213,7 @@ AddNewMovie.propTypes = {
|
|||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
hasExistingMovies: PropTypes.bool.isRequired,
|
hasExistingMovies: PropTypes.bool.isRequired,
|
||||||
onMovieLookupChange: PropTypes.func.isRequired,
|
onMovieLookupChange: PropTypes.func.isRequired,
|
||||||
onClearMovieLookup: PropTypes.func.isRequired,
|
onClearMovieLookup: PropTypes.func.isRequired
|
||||||
colorImpairedMode: PropTypes.bool.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddNewMovie;
|
export default AddNewMovie;
|
||||||
|
|||||||
@@ -3,10 +3,8 @@ import React, { Component } from 'react';
|
|||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { createSelector } from 'reselect';
|
import { createSelector } from 'reselect';
|
||||||
import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions';
|
import { clearAddMovie, lookupMovie } from 'Store/Actions/addMovieActions';
|
||||||
import { clearQueueDetails, fetchQueueDetails } from 'Store/Actions/queueActions';
|
|
||||||
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
import { fetchRootFolders } from 'Store/Actions/rootFolderActions';
|
||||||
import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions';
|
import { fetchImportExclusions } from 'Store/Actions/Settings/importExclusions';
|
||||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
|
||||||
import parseUrl from 'Utilities/String/parseUrl';
|
import parseUrl from 'Utilities/String/parseUrl';
|
||||||
import AddNewMovie from './AddNewMovie';
|
import AddNewMovie from './AddNewMovie';
|
||||||
|
|
||||||
@@ -15,15 +13,13 @@ function createMapStateToProps() {
|
|||||||
(state) => state.addMovie,
|
(state) => state.addMovie,
|
||||||
(state) => state.movies.items.length,
|
(state) => state.movies.items.length,
|
||||||
(state) => state.router.location,
|
(state) => state.router.location,
|
||||||
createUISettingsSelector(),
|
(addMovie, existingMoviesCount, location) => {
|
||||||
(addMovie, existingMoviesCount, location, uiSettings) => {
|
|
||||||
const { params } = parseUrl(location.search);
|
const { params } = parseUrl(location.search);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
...addMovie,
|
...addMovie,
|
||||||
term: params.term,
|
term: params.term,
|
||||||
hasExistingMovies: existingMoviesCount > 0,
|
hasExistingMovies: existingMoviesCount > 0
|
||||||
colorImpairedMode: uiSettings.enableColorImpairedMode
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
@@ -33,9 +29,7 @@ const mapDispatchToProps = {
|
|||||||
lookupMovie,
|
lookupMovie,
|
||||||
clearAddMovie,
|
clearAddMovie,
|
||||||
fetchRootFolders,
|
fetchRootFolders,
|
||||||
fetchImportExclusions,
|
fetchImportExclusions
|
||||||
fetchQueueDetails,
|
|
||||||
clearQueueDetails
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class AddNewMovieConnector extends Component {
|
class AddNewMovieConnector extends Component {
|
||||||
@@ -52,7 +46,6 @@ class AddNewMovieConnector extends Component {
|
|||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
this.props.fetchRootFolders();
|
this.props.fetchRootFolders();
|
||||||
this.props.fetchImportExclusions();
|
this.props.fetchImportExclusions();
|
||||||
this.props.fetchQueueDetails();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
componentWillUnmount() {
|
componentWillUnmount() {
|
||||||
@@ -61,7 +54,6 @@ class AddNewMovieConnector extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.props.clearAddMovie();
|
this.props.clearAddMovie();
|
||||||
this.props.clearQueueDetails();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -110,9 +102,7 @@ AddNewMovieConnector.propTypes = {
|
|||||||
lookupMovie: PropTypes.func.isRequired,
|
lookupMovie: PropTypes.func.isRequired,
|
||||||
clearAddMovie: PropTypes.func.isRequired,
|
clearAddMovie: PropTypes.func.isRequired,
|
||||||
fetchRootFolders: PropTypes.func.isRequired,
|
fetchRootFolders: PropTypes.func.isRequired,
|
||||||
fetchImportExclusions: PropTypes.func.isRequired,
|
fetchImportExclusions: PropTypes.func.isRequired
|
||||||
fetchQueueDetails: PropTypes.func.isRequired,
|
|
||||||
clearQueueDetails: PropTypes.func.isRequired
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
export default connect(createMapStateToProps, mapDispatchToProps)(AddNewMovieConnector);
|
||||||
|
|||||||
@@ -27,11 +27,9 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.poster {
|
.poster {
|
||||||
position: relative;
|
flex: 0 0 170px;
|
||||||
display: block;
|
|
||||||
margin-right: 20px;
|
margin-right: 20px;
|
||||||
height: 250px;
|
height: 250px;
|
||||||
background-color: $defaultColor;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.content {
|
.content {
|
||||||
@@ -88,28 +86,6 @@
|
|||||||
pointer-events: all;
|
pointer-events: all;
|
||||||
}
|
}
|
||||||
|
|
||||||
.posterContainer {
|
|
||||||
position: relative;
|
|
||||||
}
|
|
||||||
|
|
||||||
.certification {
|
|
||||||
margin-left: 2px;
|
|
||||||
padding: 0 5px;
|
|
||||||
border: 1px solid;
|
|
||||||
border-radius: 5px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.runtime {
|
|
||||||
margin-left: 8px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.statusContainer {
|
|
||||||
margin-right: 22px;
|
|
||||||
font-weight: bold;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointMedium) {
|
@media only screen and (max-width: $breakpointMedium) {
|
||||||
.titleRow {
|
.titleRow {
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|||||||
@@ -7,10 +7,7 @@ import Link from 'Components/Link/Link';
|
|||||||
import Tooltip from 'Components/Tooltip/Tooltip';
|
import Tooltip from 'Components/Tooltip/Tooltip';
|
||||||
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
import { icons, kinds, sizes, tooltipPositions } from 'Helpers/Props';
|
||||||
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
|
import MovieDetailsLinks from 'Movie/Details/MovieDetailsLinks';
|
||||||
import MovieStatusLabel from 'Movie/Details/MovieStatusLabel';
|
|
||||||
import MovieIndexProgressBar from 'Movie/Index/ProgressBar/MovieIndexProgressBar';
|
|
||||||
import MoviePoster from 'Movie/MoviePoster';
|
import MoviePoster from 'Movie/MoviePoster';
|
||||||
import formatRuntime from 'Utilities/Date/formatRuntime';
|
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import AddNewMovieModal from './AddNewMovieModal';
|
import AddNewMovieModal from './AddNewMovieModal';
|
||||||
import styles from './AddNewMovieSearchResult.css';
|
import styles from './AddNewMovieSearchResult.css';
|
||||||
@@ -68,17 +65,7 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
images,
|
images,
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
isExclusionMovie,
|
isExclusionMovie,
|
||||||
isSmallScreen,
|
isSmallScreen
|
||||||
colorImpairedMode,
|
|
||||||
id,
|
|
||||||
monitored,
|
|
||||||
hasFile,
|
|
||||||
isAvailable,
|
|
||||||
queueStatus,
|
|
||||||
queueState,
|
|
||||||
runtime,
|
|
||||||
movieRuntimeFormat,
|
|
||||||
certification
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -98,30 +85,12 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
{
|
{
|
||||||
isSmallScreen ?
|
isSmallScreen ?
|
||||||
null :
|
null :
|
||||||
<div>
|
<MoviePoster
|
||||||
<div className={styles.posterContainer}>
|
className={styles.poster}
|
||||||
<MoviePoster
|
images={images}
|
||||||
className={styles.poster}
|
size={250}
|
||||||
images={images}
|
overflow={true}
|
||||||
size={250}
|
/>
|
||||||
overflow={true}
|
|
||||||
/>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
|
||||||
isExistingMovie &&
|
|
||||||
<MovieIndexProgressBar
|
|
||||||
monitored={monitored}
|
|
||||||
hasFile={hasFile}
|
|
||||||
status={status}
|
|
||||||
posterWidth={167}
|
|
||||||
detailedProgressBar={true}
|
|
||||||
queueStatus={queueStatus}
|
|
||||||
queueState={queueState}
|
|
||||||
isAvailable={isAvailable}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
|
|
||||||
<div className={styles.content}>
|
<div className={styles.content}>
|
||||||
@@ -164,26 +133,10 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div>
|
|
||||||
{
|
|
||||||
!!certification &&
|
|
||||||
<span className={styles.certification}>
|
|
||||||
{certification}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
!!runtime &&
|
|
||||||
<span className={styles.runtime}>
|
|
||||||
{formatRuntime(runtime, movieRuntimeFormat)}
|
|
||||||
</span>
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<Label size={sizes.LARGE}>
|
<Label size={sizes.LARGE}>
|
||||||
<HeartRating
|
<HeartRating
|
||||||
ratings={ratings}
|
rating={ratings.value}
|
||||||
iconSize={13}
|
iconSize={13}
|
||||||
/>
|
/>
|
||||||
</Label>
|
</Label>
|
||||||
@@ -223,15 +176,13 @@ class AddNewMovieSearchResult extends Component {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
{
|
{
|
||||||
isExistingMovie && isSmallScreen &&
|
status === 'ended' &&
|
||||||
<MovieStatusLabel
|
<Label
|
||||||
hasMovieFiles={hasFile}
|
kind={kinds.DANGER}
|
||||||
monitored={monitored}
|
size={sizes.LARGE}
|
||||||
isAvailable={isAvailable}
|
>
|
||||||
id={id}
|
Ended
|
||||||
useLabel={true}
|
</Label>
|
||||||
colorImpairedMode={colorImpairedMode}
|
|
||||||
/>
|
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -271,18 +222,7 @@ AddNewMovieSearchResult.propTypes = {
|
|||||||
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
images: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
isExistingMovie: PropTypes.bool.isRequired,
|
isExistingMovie: PropTypes.bool.isRequired,
|
||||||
isExclusionMovie: PropTypes.bool.isRequired,
|
isExclusionMovie: PropTypes.bool.isRequired,
|
||||||
isSmallScreen: PropTypes.bool.isRequired,
|
isSmallScreen: PropTypes.bool.isRequired
|
||||||
id: PropTypes.number,
|
|
||||||
queueItems: PropTypes.arrayOf(PropTypes.object),
|
|
||||||
monitored: PropTypes.bool.isRequired,
|
|
||||||
hasFile: PropTypes.bool.isRequired,
|
|
||||||
isAvailable: PropTypes.bool.isRequired,
|
|
||||||
colorImpairedMode: PropTypes.bool,
|
|
||||||
queueStatus: PropTypes.string,
|
|
||||||
queueState: PropTypes.string,
|
|
||||||
runtime: PropTypes.number.isRequired,
|
|
||||||
movieRuntimeFormat: PropTypes.string.isRequired,
|
|
||||||
certification: PropTypes.string
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AddNewMovieSearchResult;
|
export default AddNewMovieSearchResult;
|
||||||
|
|||||||
@@ -10,17 +10,11 @@ function createMapStateToProps() {
|
|||||||
createExistingMovieSelector(),
|
createExistingMovieSelector(),
|
||||||
createExclusionMovieSelector(),
|
createExclusionMovieSelector(),
|
||||||
createDimensionsSelector(),
|
createDimensionsSelector(),
|
||||||
(state) => state.queue.details.items,
|
(isExistingMovie, isExclusionMovie, dimensions) => {
|
||||||
(state, { internalId }) => internalId,
|
|
||||||
(isExistingMovie, isExclusionMovie, dimensions, queueItems, internalId) => {
|
|
||||||
const firstQueueItem = queueItems.find((q) => q.movieId === internalId && internalId > 0);
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
isExistingMovie,
|
isExistingMovie,
|
||||||
isExclusionMovie,
|
isExclusionMovie,
|
||||||
isSmallScreen: dimensions.isSmallScreen,
|
isSmallScreen: dimensions.isSmallScreen
|
||||||
queueStatus: firstQueueItem ? firstQueueItem.status : null,
|
|
||||||
queueState: firstQueueItem ? firstQueueItem.trackedDownloadState : null
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -30,9 +30,3 @@
|
|||||||
.importButtonIcon {
|
.importButtonIcon {
|
||||||
margin-right: 8px;
|
margin-right: 8px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.addErrorAlert {
|
|
||||||
composes: alert from '~Components/Alert.css';
|
|
||||||
|
|
||||||
margin: 20px 0;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import Alert from 'Components/Alert';
|
|
||||||
import FieldSet from 'Components/FieldSet';
|
import FieldSet from 'Components/FieldSet';
|
||||||
import FileBrowserModal from 'Components/FileBrowser/FileBrowserModal';
|
import FileBrowserModal from 'Components/FileBrowser/FileBrowserModal';
|
||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
@@ -73,29 +72,23 @@ class ImportMovieSelectFolder extends Component {
|
|||||||
isWindows,
|
isWindows,
|
||||||
isFetching,
|
isFetching,
|
||||||
isPopulated,
|
isPopulated,
|
||||||
isSaving,
|
|
||||||
error,
|
error,
|
||||||
saveError,
|
|
||||||
items
|
items
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const hasRootFolders = items.length > 0;
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContent title={translate('ImportMovies')}>
|
<PageContent title={translate('ImportMovies')}>
|
||||||
<PageContentBody>
|
<PageContentBody>
|
||||||
{
|
{
|
||||||
isFetching && !isPopulated ?
|
isFetching && !isPopulated &&
|
||||||
<LoadingIndicator /> :
|
<LoadingIndicator />
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
!isFetching && error ?
|
!isFetching && !!error &&
|
||||||
<div>
|
<div>
|
||||||
{translate('UnableToLoadRootFolders')}
|
{translate('UnableToLoadRootFolders')}
|
||||||
</div> :
|
</div>
|
||||||
null
|
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
@@ -115,7 +108,7 @@ class ImportMovieSelectFolder extends Component {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
hasRootFolders ?
|
items.length > 0 ?
|
||||||
<div className={styles.recentFolders}>
|
<div className={styles.recentFolders}>
|
||||||
<FieldSet legend={translate('RecentFolders')}>
|
<FieldSet legend={translate('RecentFolders')}>
|
||||||
<Table
|
<Table
|
||||||
@@ -138,51 +131,35 @@ class ImportMovieSelectFolder extends Component {
|
|||||||
</TableBody>
|
</TableBody>
|
||||||
</Table>
|
</Table>
|
||||||
</FieldSet>
|
</FieldSet>
|
||||||
|
|
||||||
|
<Button
|
||||||
|
kind={kinds.PRIMARY}
|
||||||
|
size={sizes.LARGE}
|
||||||
|
onPress={this.onAddNewRootFolderPress}
|
||||||
|
>
|
||||||
|
<Icon
|
||||||
|
className={styles.importButtonIcon}
|
||||||
|
name={icons.DRIVE}
|
||||||
|
/>
|
||||||
|
{translate('ChooseAnotherFolder')}
|
||||||
|
</Button>
|
||||||
</div> :
|
</div> :
|
||||||
null
|
|
||||||
|
<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>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
!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
|
<FileBrowserModal
|
||||||
isOpen={this.state.isAddNewRootFolderModalOpen}
|
isOpen={this.state.isAddNewRootFolderModalOpen}
|
||||||
name="rootFolderPath"
|
name="rootFolderPath"
|
||||||
@@ -202,9 +179,7 @@ ImportMovieSelectFolder.propTypes = {
|
|||||||
isWindows: PropTypes.bool.isRequired,
|
isWindows: PropTypes.bool.isRequired,
|
||||||
isFetching: PropTypes.bool.isRequired,
|
isFetching: PropTypes.bool.isRequired,
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
isSaving: PropTypes.bool.isRequired,
|
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
saveError: PropTypes.object,
|
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
onNewRootFolderSelect: PropTypes.func.isRequired,
|
onNewRootFolderSelect: PropTypes.func.isRequired,
|
||||||
onDeleteRootFolderPress: PropTypes.func.isRequired
|
onDeleteRootFolderPress: PropTypes.func.isRequired
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { Redirect, Route } from 'react-router-dom';
|
import { Redirect, Route } from 'react-router-dom';
|
||||||
import BlocklistConnector from 'Activity/Blocklist/BlocklistConnector';
|
import BlacklistConnector from 'Activity/Blacklist/BlacklistConnector';
|
||||||
import HistoryConnector from 'Activity/History/HistoryConnector';
|
import HistoryConnector from 'Activity/History/HistoryConnector';
|
||||||
import QueueConnector from 'Activity/Queue/QueueConnector';
|
import QueueConnector from 'Activity/Queue/QueueConnector';
|
||||||
import AddNewMovieConnector from 'AddMovie/AddNewMovie/AddNewMovieConnector';
|
import AddNewMovieConnector from 'AddMovie/AddNewMovie/AddNewMovieConnector';
|
||||||
@@ -111,8 +111,8 @@ function AppRoutes(props) {
|
|||||||
/>
|
/>
|
||||||
|
|
||||||
<Route
|
<Route
|
||||||
path="/activity/blocklist"
|
path="/activity/blacklist"
|
||||||
component={BlocklistConnector}
|
component={BlacklistConnector}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
{/*
|
{/*
|
||||||
|
|||||||
@@ -11,47 +11,9 @@ import UpdateChanges from 'System/Updates/UpdateChanges';
|
|||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './AppUpdatedModalContent.css';
|
import styles from './AppUpdatedModalContent.css';
|
||||||
|
|
||||||
function mergeUpdates(items, version, prevVersion) {
|
|
||||||
let installedIndex = items.findIndex((u) => u.version === version);
|
|
||||||
let installedPreviouslyIndex = items.findIndex((u) => u.version === prevVersion);
|
|
||||||
|
|
||||||
if (installedIndex === -1) {
|
|
||||||
installedIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (installedPreviouslyIndex === -1) {
|
|
||||||
installedPreviouslyIndex = items.length;
|
|
||||||
} else if (installedPreviouslyIndex === installedIndex && items.length) {
|
|
||||||
installedPreviouslyIndex += 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const appliedUpdates = items.slice(installedIndex, installedPreviouslyIndex);
|
|
||||||
|
|
||||||
if (!appliedUpdates.length) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const appliedChanges = { new: [], fixed: [] };
|
|
||||||
appliedUpdates.forEach((u) => {
|
|
||||||
if (u.changes) {
|
|
||||||
appliedChanges.new.push(... u.changes.new);
|
|
||||||
appliedChanges.fixed.push(... u.changes.fixed);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const mergedUpdate = Object.assign({}, appliedUpdates[0], { changes: appliedChanges });
|
|
||||||
|
|
||||||
if (!appliedChanges.new.length && !appliedChanges.fixed.length) {
|
|
||||||
mergedUpdate.changes = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mergedUpdate;
|
|
||||||
}
|
|
||||||
|
|
||||||
function AppUpdatedModalContent(props) {
|
function AppUpdatedModalContent(props) {
|
||||||
const {
|
const {
|
||||||
version,
|
version,
|
||||||
prevVersion,
|
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items,
|
items,
|
||||||
@@ -59,7 +21,7 @@ function AppUpdatedModalContent(props) {
|
|||||||
onModalClose
|
onModalClose
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
const update = mergeUpdates(items, version, prevVersion);
|
const update = items[0];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<ModalContent onModalClose={onModalClose}>
|
<ModalContent onModalClose={onModalClose}>
|
||||||
@@ -127,7 +89,6 @@ function AppUpdatedModalContent(props) {
|
|||||||
|
|
||||||
AppUpdatedModalContent.propTypes = {
|
AppUpdatedModalContent.propTypes = {
|
||||||
version: PropTypes.string.isRequired,
|
version: PropTypes.string.isRequired,
|
||||||
prevVersion: PropTypes.string,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
isPopulated: PropTypes.bool.isRequired,
|
||||||
error: PropTypes.object,
|
error: PropTypes.object,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
|
|||||||
@@ -8,9 +8,8 @@ import AppUpdatedModalContent from './AppUpdatedModalContent';
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.app.version,
|
(state) => state.app.version,
|
||||||
(state) => state.app.prevVersion,
|
|
||||||
(state) => state.system.updates,
|
(state) => state.system.updates,
|
||||||
(version, prevVersion, updates) => {
|
(version, updates) => {
|
||||||
const {
|
const {
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
@@ -19,7 +18,6 @@ function createMapStateToProps() {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
version,
|
version,
|
||||||
prevVersion,
|
|
||||||
isPopulated,
|
isPopulated,
|
||||||
error,
|
error,
|
||||||
items
|
items
|
||||||
|
|||||||
@@ -29,7 +29,7 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.time {
|
.time {
|
||||||
flex: 0 0 125px;
|
flex: 0 0 120px;
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
border: none !important;
|
border: none !important;
|
||||||
}
|
}
|
||||||
@@ -54,24 +54,20 @@
|
|||||||
composes: downloaded from '~Calendar/Events/CalendarEvent.css';
|
composes: downloaded from '~Calendar/Events/CalendarEvent.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue {
|
.downloading {
|
||||||
composes: queue from '~Calendar/Events/CalendarEvent.css';
|
composes: downloading from '~Calendar/Events/CalendarEvent.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
.unmonitored {
|
.unmonitored {
|
||||||
composes: unmonitored from '~Calendar/Events/CalendarEvent.css';
|
composes: unmonitored from '~Calendar/Events/CalendarEvent.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
.missingUnmonitored {
|
.missing {
|
||||||
composes: missingUnmonitored from '~Calendar/Events/CalendarEvent.css';
|
composes: missing from '~Calendar/Events/CalendarEvent.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
.missingMonitored {
|
.unreleased {
|
||||||
composes: missingMonitored from '~Calendar/Events/CalendarEvent.css';
|
composes: unreleased from '~Calendar/Events/CalendarEvent.css';
|
||||||
}
|
|
||||||
|
|
||||||
.continuing {
|
|
||||||
composes: continuing from '~Calendar/Events/CalendarEvent.css';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@media only screen and (max-width: $breakpointSmall) {
|
@media only screen and (max-width: $breakpointSmall) {
|
||||||
|
|||||||
@@ -3,10 +3,10 @@ import moment from 'moment';
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import CalendarEventQueueDetails from 'Calendar/Events/CalendarEventQueueDetails';
|
import CalendarEventQueueDetails from 'Calendar/Events/CalendarEventQueueDetails';
|
||||||
|
import getStatusStyle from 'Calendar/getStatusStyle';
|
||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import { icons, kinds } from 'Helpers/Props';
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
|
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import styles from './AgendaEvent.css';
|
import styles from './AgendaEvent.css';
|
||||||
|
|
||||||
@@ -82,7 +82,7 @@ class AgendaEvent extends Component {
|
|||||||
startTime = moment(startTime);
|
startTime = moment(startTime);
|
||||||
const downloading = !!(queueItem || grabbed);
|
const downloading = !!(queueItem || grabbed);
|
||||||
const isMonitored = monitored;
|
const isMonitored = monitored;
|
||||||
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', downloading);
|
const statusStyle = getStatusStyle(hasFile, downloading, isAvailable, isMonitored);
|
||||||
const joinedGenres = genres.slice(0, 2).join(', ');
|
const joinedGenres = genres.slice(0, 2).join(', ');
|
||||||
const link = `/movie/${titleSlug}`;
|
const link = `/movie/${titleSlug}`;
|
||||||
|
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function createMissingMovieIdsSelector() {
|
|||||||
const inCinemas = movie.inCinemas;
|
const inCinemas = movie.inCinemas;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
!movie.hasFile &&
|
!movie.movieFileId &&
|
||||||
moment(inCinemas).isAfter(start) &&
|
moment(inCinemas).isAfter(start) &&
|
||||||
moment(inCinemas).isBefore(end) &&
|
moment(inCinemas).isBefore(end) &&
|
||||||
isBefore(movie.inCinemas) &&
|
isBefore(movie.inCinemas) &&
|
||||||
|
|||||||
@@ -60,30 +60,39 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue {
|
.downloading {
|
||||||
border-left-color: $purple !important;
|
border-left-color: $purple !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unmonitored {
|
.unmonitored {
|
||||||
border-left-color: $gray !important;
|
border-left-color: $gray !important;
|
||||||
}
|
|
||||||
|
|
||||||
.missingUnmonitored {
|
|
||||||
border-left-color: $warningColor !important;
|
|
||||||
|
|
||||||
&:global(.colorImpaired) {
|
&:global(.colorImpaired) {
|
||||||
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
background: repeating-linear-gradient(45deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.missingMonitored {
|
.onAir {
|
||||||
border-left-color: $dangerColor !important;
|
border-left-color: $warningColor !important;
|
||||||
|
|
||||||
&:global(.colorImpaired) {
|
&:global(.colorImpaired) {
|
||||||
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
background: repeating-linear-gradient(90deg, $colorImpairedGradientDark, $colorImpairedGradientDark 5px, $colorImpairedGradient 5px, $colorImpairedGradient 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.continuing {
|
.missing {
|
||||||
border-left-color: $primaryColor !important;
|
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 {
|
||||||
|
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 moment from 'moment';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import getStatusStyle from 'Calendar/getStatusStyle';
|
||||||
import Icon from 'Components/Icon';
|
import Icon from 'Components/Icon';
|
||||||
import Link from 'Components/Link/Link';
|
import Link from 'Components/Link/Link';
|
||||||
import { icons, kinds } from 'Helpers/Props';
|
import { icons, kinds } from 'Helpers/Props';
|
||||||
import getStatusStyle from 'Utilities/Movie/getStatusStyle';
|
|
||||||
import translate from 'Utilities/String/translate';
|
import translate from 'Utilities/String/translate';
|
||||||
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
|
import CalendarEventQueueDetails from './CalendarEventQueueDetails';
|
||||||
import styles from './CalendarEvent.css';
|
import styles from './CalendarEvent.css';
|
||||||
@@ -38,20 +38,20 @@ class CalendarEvent extends Component {
|
|||||||
|
|
||||||
const isDownloading = !!(queueItem || grabbed);
|
const isDownloading = !!(queueItem || grabbed);
|
||||||
const isMonitored = monitored;
|
const isMonitored = monitored;
|
||||||
const statusStyle = getStatusStyle(null, isMonitored, hasFile, isAvailable, 'style', isDownloading);
|
const statusStyle = getStatusStyle(hasFile, isDownloading, isAvailable, isMonitored);
|
||||||
const joinedGenres = genres.slice(0, 2).join(', ');
|
const joinedGenres = genres.slice(0, 2).join(', ');
|
||||||
const link = `/movie/${titleSlug}`;
|
const link = `/movie/${titleSlug}`;
|
||||||
const eventType = [];
|
const eventType = [];
|
||||||
|
|
||||||
if (inCinemas && moment(date).isSame(moment(inCinemas), 'day')) {
|
if (moment(date).isSame(moment(inCinemas), 'day')) {
|
||||||
eventType.push('Cinemas');
|
eventType.push('Cinemas');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (physicalRelease && moment(date).isSame(moment(physicalRelease), 'day')) {
|
if (moment(date).isSame(moment(physicalRelease), 'day')) {
|
||||||
eventType.push('Physical');
|
eventType.push('Physical');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (digitalRelease && moment(date).isSame(moment(digitalRelease), 'day')) {
|
if (moment(date).isSame(moment(digitalRelease), 'day')) {
|
||||||
eventType.push('Digital');
|
eventType.push('Digital');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,23 @@
|
|||||||
|
|
||||||
|
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;
|
||||||
@@ -22,7 +22,7 @@ function getUrls(state) {
|
|||||||
tags
|
tags
|
||||||
} = state;
|
} = state;
|
||||||
|
|
||||||
let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/v3/calendar/Radarr.ics?`;
|
let icalUrl = `${window.location.host}${window.Radarr.urlBase}/feed/calendar/Radarr.ics?`;
|
||||||
|
|
||||||
if (unmonitored) {
|
if (unmonitored) {
|
||||||
icalUrl += 'unmonitored=true&';
|
icalUrl += 'unmonitored=true&';
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
export const APPLICATION_UPDATE = 'ApplicationUpdate';
|
export const APPLICATION_UPDATE = 'ApplicationUpdate';
|
||||||
export const BACKUP = 'Backup';
|
export const BACKUP = 'Backup';
|
||||||
export const REFRESH_MONITORED_DOWNLOADS = 'RefreshMonitoredDownloads';
|
export const REFRESH_MONITORED_DOWNLOADS = 'RefreshMonitoredDownloads';
|
||||||
export const CLEAR_BLOCKLIST = 'ClearBlocklist';
|
export const CLEAR_BLACKLIST = 'ClearBlacklist';
|
||||||
export const CLEAR_LOGS = 'ClearLog';
|
export const CLEAR_LOGS = 'ClearLog';
|
||||||
export const CUTOFF_UNMET_MOVIES_SEARCH = 'CutoffUnmetMoviesSearch';
|
export const CUTOFF_UNMET_MOVIES_SEARCH = 'CutoffUnmetMoviesSearch';
|
||||||
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
export const DELETE_LOG_FILES = 'DeleteLogFiles';
|
||||||
|
|||||||
@@ -16,9 +16,4 @@
|
|||||||
color: #3a3f51;
|
color: #3a3f51;
|
||||||
font-size: 21px;
|
font-size: 21px;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
|
|
||||||
&.small {
|
|
||||||
color: #909293;
|
|
||||||
font-size: 18px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,5 @@
|
|||||||
import classNames from 'classnames';
|
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { sizes } from 'Helpers/Props';
|
|
||||||
import styles from './FieldSet.css';
|
import styles from './FieldSet.css';
|
||||||
|
|
||||||
class FieldSet extends Component {
|
class FieldSet extends Component {
|
||||||
@@ -11,14 +9,13 @@ class FieldSet extends Component {
|
|||||||
|
|
||||||
render() {
|
render() {
|
||||||
const {
|
const {
|
||||||
size,
|
|
||||||
legend,
|
legend,
|
||||||
children
|
children
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<fieldset className={styles.fieldSet}>
|
<fieldset className={styles.fieldSet}>
|
||||||
<legend className={classNames(styles.legend, (size === sizes.SMALL) && styles.small)}>
|
<legend className={styles.legend}>
|
||||||
{legend}
|
{legend}
|
||||||
</legend>
|
</legend>
|
||||||
{children}
|
{children}
|
||||||
@@ -29,13 +26,8 @@ class FieldSet extends Component {
|
|||||||
}
|
}
|
||||||
|
|
||||||
FieldSet.propTypes = {
|
FieldSet.propTypes = {
|
||||||
size: PropTypes.oneOf(sizes.all).isRequired,
|
|
||||||
legend: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
|
legend: PropTypes.oneOfType([PropTypes.node, PropTypes.string]),
|
||||||
children: PropTypes.node
|
children: PropTypes.node
|
||||||
};
|
};
|
||||||
|
|
||||||
FieldSet.defaultProps = {
|
|
||||||
size: sizes.MEDIUM
|
|
||||||
};
|
|
||||||
|
|
||||||
export default FieldSet;
|
export default FieldSet;
|
||||||
|
|||||||
@@ -129,7 +129,7 @@ class FileBrowserModalContent extends Component {
|
|||||||
className={styles.mappedDrivesWarning}
|
className={styles.mappedDrivesWarning}
|
||||||
kind={kinds.WARNING}
|
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')}
|
{translate('MappedDrivesRunningAsService')}
|
||||||
</Link> .
|
</Link> .
|
||||||
</Alert>
|
</Alert>
|
||||||
|
|||||||
@@ -166,9 +166,7 @@ class FilterBuilderModalContent extends Component {
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={styles.label}>
|
<div className={styles.label}>Filters</div>
|
||||||
{translate('Filters')}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className={styles.rows}>
|
<div className={styles.rows}>
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ function createTagListSelector() {
|
|||||||
(selectedFilterBuilderProp.type === filterBuilderTypes.NUMBER ||
|
(selectedFilterBuilderProp.type === filterBuilderTypes.NUMBER ||
|
||||||
selectedFilterBuilderProp.type === filterBuilderTypes.STRING) &&
|
selectedFilterBuilderProp.type === filterBuilderTypes.STRING) &&
|
||||||
filterType !== filterTypes.EQUAL &&
|
filterType !== filterTypes.EQUAL &&
|
||||||
filterType !== filterTypes.NOT_EQUAL ||
|
filterType !== filterBuilderTypes.NOT_EQUAL ||
|
||||||
!selectedFilterBuilderProp.optionsSelector
|
!selectedFilterBuilderProp.optionsSelector
|
||||||
) {
|
) {
|
||||||
return [];
|
return [];
|
||||||
|
|||||||
@@ -6,7 +6,8 @@ import SelectInput from './SelectInput';
|
|||||||
const availabilityOptions = [
|
const availabilityOptions = [
|
||||||
{ key: 'announced', value: translate('Announced') },
|
{ key: 'announced', value: translate('Announced') },
|
||||||
{ key: 'inCinemas', value: translate('InCinemas') },
|
{ key: 'inCinemas', value: translate('InCinemas') },
|
||||||
{ key: 'released', value: translate('Released') }
|
{ key: 'released', value: translate('Released') },
|
||||||
|
{ key: 'preDB', value: translate('PreDB') }
|
||||||
];
|
];
|
||||||
|
|
||||||
function AvailabilitySelectInput(props) {
|
function AvailabilitySelectInput(props) {
|
||||||
|
|||||||
@@ -1,100 +0,0 @@
|
|||||||
import _ from 'lodash';
|
|
||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import { fetchDownloadClients } from 'Store/Actions/settingsActions';
|
|
||||||
import sortByName from 'Utilities/Array/sortByName';
|
|
||||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state) => state.settings.downloadClients,
|
|
||||||
(state, { includeAny }) => includeAny,
|
|
||||||
(state, { protocol }) => protocol,
|
|
||||||
(downloadClients, includeAny, protocolFilter) => {
|
|
||||||
const {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
items
|
|
||||||
} = downloadClients;
|
|
||||||
|
|
||||||
const filteredItems = items.filter((item) => item.protocol === protocolFilter);
|
|
||||||
|
|
||||||
const values = _.map(filteredItems.sort(sortByName), (downloadClient) => {
|
|
||||||
return {
|
|
||||||
key: downloadClient.id,
|
|
||||||
value: downloadClient.name
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
if (includeAny) {
|
|
||||||
values.unshift({
|
|
||||||
key: 0,
|
|
||||||
value: '(Any)'
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
|
||||||
isFetching,
|
|
||||||
isPopulated,
|
|
||||||
error,
|
|
||||||
values
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
const mapDispatchToProps = {
|
|
||||||
dispatchFetchDownloadClients: fetchDownloadClients
|
|
||||||
};
|
|
||||||
|
|
||||||
class DownloadClientSelectInputConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Lifecycle
|
|
||||||
|
|
||||||
componentDidMount() {
|
|
||||||
if (!this.props.isPopulated) {
|
|
||||||
this.props.dispatchFetchDownloadClients();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Listeners
|
|
||||||
|
|
||||||
onChange = ({ name, value }) => {
|
|
||||||
this.props.onChange({ name, value: parseInt(value) });
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return (
|
|
||||||
<EnhancedSelectInput
|
|
||||||
{...this.props}
|
|
||||||
onChange={this.onChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
DownloadClientSelectInputConnector.propTypes = {
|
|
||||||
isFetching: PropTypes.bool.isRequired,
|
|
||||||
isPopulated: PropTypes.bool.isRequired,
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.oneOfType([PropTypes.number, PropTypes.string]).isRequired,
|
|
||||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
includeAny: PropTypes.bool.isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired,
|
|
||||||
dispatchFetchDownloadClients: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
DownloadClientSelectInputConnector.defaultProps = {
|
|
||||||
includeAny: false,
|
|
||||||
protocol: 'torrent'
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps, mapDispatchToProps)(DownloadClientSelectInputConnector);
|
|
||||||
@@ -85,21 +85,3 @@
|
|||||||
display: inline-block;
|
display: inline-block;
|
||||||
margin: 5px -5px 5px 0;
|
margin: 5px -5px 5px 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
.mobileCloseButtonContainer {
|
|
||||||
display: flex;
|
|
||||||
justify-content: flex-end;
|
|
||||||
height: 40px;
|
|
||||||
border-bottom: 1px solid $borderColor;
|
|
||||||
}
|
|
||||||
|
|
||||||
.mobileCloseButton {
|
|
||||||
width: 40px;
|
|
||||||
height: 40px;
|
|
||||||
text-align: center;
|
|
||||||
line-height: 40px;
|
|
||||||
|
|
||||||
&:hover {
|
|
||||||
color: $modalCloseButtonHoverColor;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -479,7 +479,6 @@ class EnhancedSelectInput extends Component {
|
|||||||
<OptionComponent
|
<OptionComponent
|
||||||
key={v.key}
|
key={v.key}
|
||||||
id={v.key}
|
id={v.key}
|
||||||
dividerAfter={v.dividerAfter}
|
|
||||||
depth={depth}
|
depth={depth}
|
||||||
isSelected={isSelectedItem(index, this.props)}
|
isSelected={isSelectedItem(index, this.props)}
|
||||||
isDisabled={parentSelected}
|
isDisabled={parentSelected}
|
||||||
@@ -519,18 +518,6 @@ class EnhancedSelectInput extends Component {
|
|||||||
scrollDirection={scrollDirections.NONE}
|
scrollDirection={scrollDirections.NONE}
|
||||||
>
|
>
|
||||||
<Scroller className={styles.optionsModalScroller}>
|
<Scroller className={styles.optionsModalScroller}>
|
||||||
<div className={styles.mobileCloseButtonContainer}>
|
|
||||||
<Link
|
|
||||||
className={styles.mobileCloseButton}
|
|
||||||
onPress={this.onOptionsModalClose}
|
|
||||||
>
|
|
||||||
<Icon
|
|
||||||
name={icons.CLOSE}
|
|
||||||
size={18}
|
|
||||||
/>
|
|
||||||
</Link>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
values.map((v, index) => {
|
values.map((v, index) => {
|
||||||
const hasParent = v.parentKey !== undefined;
|
const hasParent = v.parentKey !== undefined;
|
||||||
@@ -540,7 +527,6 @@ class EnhancedSelectInput extends Component {
|
|||||||
<OptionComponent
|
<OptionComponent
|
||||||
key={v.key}
|
key={v.key}
|
||||||
id={v.key}
|
id={v.key}
|
||||||
dividerAfter={v.dividerAfter}
|
|
||||||
depth={depth}
|
depth={depth}
|
||||||
isSelected={isSelectedItem(index, this.props)}
|
isSelected={isSelectedItem(index, this.props)}
|
||||||
isMultiSelect={isMultiSelect}
|
isMultiSelect={isMultiSelect}
|
||||||
|
|||||||
@@ -54,8 +54,4 @@
|
|||||||
&:last-child {
|
&:last-child {
|
||||||
border: none;
|
border: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: unset;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,9 +12,7 @@ class EnhancedSelectInputOption extends Component {
|
|||||||
//
|
//
|
||||||
// Listeners
|
// Listeners
|
||||||
|
|
||||||
onPress = (e) => {
|
onPress = () => {
|
||||||
e.preventDefault();
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
id,
|
id,
|
||||||
onSelect
|
onSelect
|
||||||
|
|||||||
@@ -8,13 +8,11 @@ import AvailabilitySelectInput from './AvailabilitySelectInput';
|
|||||||
import CaptchaInputConnector from './CaptchaInputConnector';
|
import CaptchaInputConnector from './CaptchaInputConnector';
|
||||||
import CheckInput from './CheckInput';
|
import CheckInput from './CheckInput';
|
||||||
import DeviceInputConnector from './DeviceInputConnector';
|
import DeviceInputConnector from './DeviceInputConnector';
|
||||||
import DownloadClientSelectInputConnector from './DownloadClientSelectInputConnector';
|
|
||||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
import EnhancedSelectInput from './EnhancedSelectInput';
|
||||||
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
|
import EnhancedSelectInputConnector from './EnhancedSelectInputConnector';
|
||||||
import FormInputHelpText from './FormInputHelpText';
|
import FormInputHelpText from './FormInputHelpText';
|
||||||
import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector';
|
import IndexerFlagsSelectInputConnector from './IndexerFlagsSelectInputConnector';
|
||||||
import KeyValueListInput from './KeyValueListInput';
|
import KeyValueListInput from './KeyValueListInput';
|
||||||
import LanguageSelectInputConnector from './LanguageSelectInputConnector';
|
|
||||||
import MovieMonitoredSelectInput from './MovieMonitoredSelectInput';
|
import MovieMonitoredSelectInput from './MovieMonitoredSelectInput';
|
||||||
import NumberInput from './NumberInput';
|
import NumberInput from './NumberInput';
|
||||||
import OAuthInputConnector from './OAuthInputConnector';
|
import OAuthInputConnector from './OAuthInputConnector';
|
||||||
@@ -74,12 +72,6 @@ function getComponent(type) {
|
|||||||
case inputTypes.INDEXER_FLAGS_SELECT:
|
case inputTypes.INDEXER_FLAGS_SELECT:
|
||||||
return IndexerFlagsSelectInputConnector;
|
return IndexerFlagsSelectInputConnector;
|
||||||
|
|
||||||
case inputTypes.DOWNLOAD_CLIENT_SELECT:
|
|
||||||
return DownloadClientSelectInputConnector;
|
|
||||||
|
|
||||||
case inputTypes.LANGUAGE_SELECT:
|
|
||||||
return LanguageSelectInputConnector;
|
|
||||||
|
|
||||||
case inputTypes.SELECT:
|
case inputTypes.SELECT:
|
||||||
return EnhancedSelectInput;
|
return EnhancedSelectInput;
|
||||||
|
|
||||||
|
|||||||
@@ -21,8 +21,3 @@
|
|||||||
color: $darkGray;
|
color: $darkGray;
|
||||||
font-size: $smallFontSize;
|
font-size: $smallFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.divider {
|
|
||||||
border: none;
|
|
||||||
border-bottom: 1px solid $lightGray;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -12,46 +12,37 @@ function HintedSelectInputOption(props) {
|
|||||||
depth,
|
depth,
|
||||||
isSelected,
|
isSelected,
|
||||||
isDisabled,
|
isDisabled,
|
||||||
dividerAfter,
|
|
||||||
isMultiSelect,
|
isMultiSelect,
|
||||||
isMobile,
|
isMobile,
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div>
|
<EnhancedSelectInputOption
|
||||||
<EnhancedSelectInputOption
|
id={id}
|
||||||
id={id}
|
depth={depth}
|
||||||
depth={depth}
|
isSelected={isSelected}
|
||||||
isSelected={isSelected}
|
isDisabled={isDisabled}
|
||||||
isDisabled={isDisabled}
|
isHidden={isDisabled}
|
||||||
isHidden={isDisabled}
|
isMultiSelect={isMultiSelect}
|
||||||
isMultiSelect={isMultiSelect}
|
isMobile={isMobile}
|
||||||
isMobile={isMobile}
|
{...otherProps}
|
||||||
{...otherProps}
|
>
|
||||||
|
<div className={classNames(
|
||||||
|
styles.optionText,
|
||||||
|
isMobile && styles.isMobile
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<div className={classNames(
|
<div>{value}</div>
|
||||||
styles.optionText,
|
|
||||||
isMobile && styles.isMobile
|
|
||||||
)}
|
|
||||||
>
|
|
||||||
<div>{value}</div>
|
|
||||||
|
|
||||||
{
|
{
|
||||||
hint != null &&
|
hint != null &&
|
||||||
<div className={styles.hintText}>
|
<div className={styles.hintText}>
|
||||||
{hint}
|
{hint}
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
</div>
|
</div>
|
||||||
</EnhancedSelectInputOption>
|
</EnhancedSelectInputOption>
|
||||||
|
|
||||||
{
|
|
||||||
dividerAfter ?
|
|
||||||
<div className={styles.divider} /> :
|
|
||||||
null
|
|
||||||
}
|
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,18 +50,15 @@ HintedSelectInputOption.propTypes = {
|
|||||||
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired,
|
||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
hint: PropTypes.node,
|
hint: PropTypes.node,
|
||||||
name: PropTypes.string,
|
|
||||||
depth: PropTypes.number,
|
depth: PropTypes.number,
|
||||||
isSelected: PropTypes.bool.isRequired,
|
isSelected: PropTypes.bool.isRequired,
|
||||||
isDisabled: PropTypes.bool.isRequired,
|
isDisabled: PropTypes.bool.isRequired,
|
||||||
dividerAfter: PropTypes.bool.isRequired,
|
|
||||||
isMultiSelect: PropTypes.bool.isRequired,
|
isMultiSelect: PropTypes.bool.isRequired,
|
||||||
isMobile: PropTypes.bool.isRequired
|
isMobile: PropTypes.bool.isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
HintedSelectInputOption.defaultProps = {
|
HintedSelectInputOption.defaultProps = {
|
||||||
isDisabled: false,
|
isDisabled: false,
|
||||||
dividerAfter: false,
|
|
||||||
isHidden: false,
|
isHidden: false,
|
||||||
isMultiSelect: false
|
isMultiSelect: false
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,52 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { connect } from 'react-redux';
|
|
||||||
import { createSelector } from 'reselect';
|
|
||||||
import EnhancedSelectInput from './EnhancedSelectInput';
|
|
||||||
|
|
||||||
function createMapStateToProps() {
|
|
||||||
return createSelector(
|
|
||||||
(state, { values }) => values,
|
|
||||||
( languages ) => {
|
|
||||||
|
|
||||||
const minId = languages.reduce((min, v) => (v.key < 1 ? v.key : min), languages[0].key);
|
|
||||||
|
|
||||||
const values = languages.map(({ key, value }) => {
|
|
||||||
return {
|
|
||||||
key,
|
|
||||||
value,
|
|
||||||
dividerAfter: minId < 1 ? key === minId : false
|
|
||||||
};
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
values
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
class LanguageSelectInputConnector extends Component {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
return (
|
|
||||||
<EnhancedSelectInput
|
|
||||||
{...this.props}
|
|
||||||
onChange={this.props.onChange}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LanguageSelectInputConnector.propTypes = {
|
|
||||||
name: PropTypes.string.isRequired,
|
|
||||||
value: PropTypes.oneOfType([PropTypes.arrayOf(PropTypes.number), PropTypes.number]).isRequired,
|
|
||||||
values: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
||||||
onChange: PropTypes.func.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
export default connect(createMapStateToProps)(LanguageSelectInputConnector);
|
|
||||||
@@ -49,7 +49,6 @@ function getSelectValues(selectOptions) {
|
|||||||
result.push({
|
result.push({
|
||||||
key: option.value,
|
key: option.value,
|
||||||
value: option.name,
|
value: option.name,
|
||||||
dividerAfter: option.dividerAfter,
|
|
||||||
hint: option.hint
|
hint: option.hint
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -64,7 +63,6 @@ function ProviderFieldFormGroup(props) {
|
|||||||
label,
|
label,
|
||||||
helpText,
|
helpText,
|
||||||
helpLink,
|
helpLink,
|
||||||
placeholder,
|
|
||||||
value,
|
value,
|
||||||
type,
|
type,
|
||||||
advanced,
|
advanced,
|
||||||
@@ -97,7 +95,6 @@ function ProviderFieldFormGroup(props) {
|
|||||||
label={label}
|
label={label}
|
||||||
helpText={helpText}
|
helpText={helpText}
|
||||||
helpLink={helpLink}
|
helpLink={helpLink}
|
||||||
placeholder={placeholder}
|
|
||||||
value={value}
|
value={value}
|
||||||
values={getSelectValues(selectOptions)}
|
values={getSelectValues(selectOptions)}
|
||||||
errors={errors}
|
errors={errors}
|
||||||
@@ -123,7 +120,6 @@ ProviderFieldFormGroup.propTypes = {
|
|||||||
label: PropTypes.string.isRequired,
|
label: PropTypes.string.isRequired,
|
||||||
helpText: PropTypes.string,
|
helpText: PropTypes.string,
|
||||||
helpLink: PropTypes.string,
|
helpLink: PropTypes.string,
|
||||||
placeholder: PropTypes.string,
|
|
||||||
value: PropTypes.any,
|
value: PropTypes.any,
|
||||||
type: PropTypes.string.isRequired,
|
type: PropTypes.string.isRequired,
|
||||||
advanced: PropTypes.bool.isRequired,
|
advanced: PropTypes.bool.isRequired,
|
||||||
|
|||||||
@@ -10,16 +10,13 @@ const ADD_NEW_KEY = 'addNew';
|
|||||||
function createMapStateToProps() {
|
function createMapStateToProps() {
|
||||||
return createSelector(
|
return createSelector(
|
||||||
(state) => state.rootFolders,
|
(state) => state.rootFolders,
|
||||||
(state, { value }) => value,
|
|
||||||
(state, { includeMissingValue }) => includeMissingValue,
|
|
||||||
(state, { includeNoChange }) => includeNoChange,
|
(state, { includeNoChange }) => includeNoChange,
|
||||||
(rootFolders, value, includeMissingValue, includeNoChange) => {
|
(rootFolders, includeNoChange) => {
|
||||||
const values = rootFolders.items.map((rootFolder) => {
|
const values = rootFolders.items.map((rootFolder) => {
|
||||||
return {
|
return {
|
||||||
key: rootFolder.path,
|
key: rootFolder.path,
|
||||||
value: rootFolder.path,
|
value: rootFolder.path,
|
||||||
freeSpace: rootFolder.freeSpace,
|
freeSpace: rootFolder.freeSpace
|
||||||
isMissing: false
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -27,8 +24,7 @@ function createMapStateToProps() {
|
|||||||
values.unshift({
|
values.unshift({
|
||||||
key: 'noChange',
|
key: 'noChange',
|
||||||
value: 'No Change',
|
value: 'No Change',
|
||||||
isDisabled: true,
|
isDisabled: true
|
||||||
isMissing: false
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,15 +37,6 @@ function createMapStateToProps() {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (includeMissingValue && !values.find((v) => v.key === value)) {
|
|
||||||
values.push({
|
|
||||||
key: value,
|
|
||||||
value,
|
|
||||||
isMissing: true,
|
|
||||||
isDisabled: true
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
values.push({
|
values.push({
|
||||||
key: ADD_NEW_KEY,
|
key: ADD_NEW_KEY,
|
||||||
value: 'Add a new path'
|
value: 'Add a new path'
|
||||||
@@ -164,8 +151,7 @@ RootFolderSelectInputConnector.propTypes = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
RootFolderSelectInputConnector.defaultProps = {
|
RootFolderSelectInputConnector.defaultProps = {
|
||||||
includeNoChange: false,
|
includeNoChange: false
|
||||||
value: ''
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default connect(createMapStateToProps, createMapDispatchToProps)(RootFolderSelectInputConnector);
|
export default connect(createMapStateToProps, createMapDispatchToProps)(RootFolderSelectInputConnector);
|
||||||
|
|||||||
@@ -29,9 +29,3 @@
|
|||||||
color: $darkGray;
|
color: $darkGray;
|
||||||
font-size: $smallFontSize;
|
font-size: $smallFontSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
.isMissing {
|
|
||||||
margin-left: 15px;
|
|
||||||
color: $dangerColor;
|
|
||||||
font-size: $smallFontSize;
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ function RootFolderSelectInputOption(props) {
|
|||||||
id,
|
id,
|
||||||
value,
|
value,
|
||||||
freeSpace,
|
freeSpace,
|
||||||
isMissing,
|
|
||||||
movieFolder,
|
movieFolder,
|
||||||
isMobile,
|
isMobile,
|
||||||
isWindows,
|
isWindows,
|
||||||
@@ -44,20 +43,11 @@ function RootFolderSelectInputOption(props) {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{
|
{
|
||||||
freeSpace == null ?
|
freeSpace != null &&
|
||||||
null :
|
|
||||||
<div className={styles.freeSpace}>
|
<div className={styles.freeSpace}>
|
||||||
{formatBytes(freeSpace)} Free
|
{formatBytes(freeSpace)} Free
|
||||||
</div>
|
</div>
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
|
||||||
isMissing ?
|
|
||||||
<div className={styles.isMissing}>
|
|
||||||
Missing
|
|
||||||
</div> :
|
|
||||||
null
|
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
</EnhancedSelectInputOption>
|
</EnhancedSelectInputOption>
|
||||||
);
|
);
|
||||||
@@ -68,7 +58,6 @@ RootFolderSelectInputOption.propTypes = {
|
|||||||
value: PropTypes.string.isRequired,
|
value: PropTypes.string.isRequired,
|
||||||
freeSpace: PropTypes.number,
|
freeSpace: PropTypes.number,
|
||||||
movieFolder: PropTypes.string,
|
movieFolder: PropTypes.string,
|
||||||
isMissing: PropTypes.boolean,
|
|
||||||
isMobile: PropTypes.bool.isRequired,
|
isMobile: PropTypes.bool.isRequired,
|
||||||
isWindows: PropTypes.bool
|
isWindows: PropTypes.bool
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
.image {
|
.heart {
|
||||||
align-content: center;
|
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
vertical-align: -0.125em;
|
color: $themeRed;
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -1,5 +0,0 @@
|
|||||||
.image {
|
|
||||||
align-content: center;
|
|
||||||
margin-right: 5px;
|
|
||||||
vertical-align: -0.125em;
|
|
||||||
}
|
|
||||||
File diff suppressed because one or more lines are too long
@@ -19,10 +19,6 @@
|
|||||||
&.outline {
|
&.outline {
|
||||||
color: $dangerColor;
|
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.default {
|
.default {
|
||||||
@@ -89,10 +85,6 @@
|
|||||||
&.outline {
|
&.outline {
|
||||||
color: $warningColor;
|
color: $warningColor;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:global(.colorImpaired) {
|
|
||||||
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.queue {
|
.queue {
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ function Label(props) {
|
|||||||
size,
|
size,
|
||||||
outline,
|
outline,
|
||||||
children,
|
children,
|
||||||
colorImpairedMode,
|
|
||||||
...otherProps
|
...otherProps
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
@@ -21,8 +20,7 @@ function Label(props) {
|
|||||||
className,
|
className,
|
||||||
styles[kind],
|
styles[kind],
|
||||||
styles[size],
|
styles[size],
|
||||||
outline && styles.outline,
|
outline && styles.outline
|
||||||
colorImpairedMode && 'colorImpaired'
|
|
||||||
)}
|
)}
|
||||||
{...otherProps}
|
{...otherProps}
|
||||||
>
|
>
|
||||||
@@ -36,16 +34,14 @@ Label.propTypes = {
|
|||||||
kind: PropTypes.oneOf(kinds.all).isRequired,
|
kind: PropTypes.oneOf(kinds.all).isRequired,
|
||||||
size: PropTypes.oneOf(sizes.all).isRequired,
|
size: PropTypes.oneOf(sizes.all).isRequired,
|
||||||
outline: PropTypes.bool.isRequired,
|
outline: PropTypes.bool.isRequired,
|
||||||
children: PropTypes.node.isRequired,
|
children: PropTypes.node.isRequired
|
||||||
colorImpairedMode: PropTypes.bool
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Label.defaultProps = {
|
Label.defaultProps = {
|
||||||
className: styles.label,
|
className: styles.label,
|
||||||
kind: kinds.DEFAULT,
|
kind: kinds.DEFAULT,
|
||||||
size: sizes.SMALL,
|
size: sizes.SMALL,
|
||||||
outline: false,
|
outline: false
|
||||||
colorImpairedMode: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export default Label;
|
export default Label;
|
||||||
|
|||||||
@@ -38,12 +38,11 @@ class Link extends Component {
|
|||||||
const linkProps = { target };
|
const linkProps = { target };
|
||||||
let el = component;
|
let el = component;
|
||||||
|
|
||||||
if (to && typeof to === 'string') {
|
if (to) {
|
||||||
if ((/\w+?:\/\//).test(to)) {
|
if ((/\w+?:\/\//).test(to)) {
|
||||||
el = 'a';
|
el = 'a';
|
||||||
linkProps.href = to;
|
linkProps.href = to;
|
||||||
linkProps.target = target || '_blank';
|
linkProps.target = target || '_blank';
|
||||||
linkProps.rel = 'noreferrer';
|
|
||||||
} else if (noRouter) {
|
} else if (noRouter) {
|
||||||
el = 'a';
|
el = 'a';
|
||||||
linkProps.href = to;
|
linkProps.href = to;
|
||||||
@@ -53,18 +52,6 @@ class Link extends Component {
|
|||||||
linkProps.to = `${window.Radarr.urlBase}/${to.replace(/^\//, '')}`;
|
linkProps.to = `${window.Radarr.urlBase}/${to.replace(/^\//, '')}`;
|
||||||
linkProps.target = target;
|
linkProps.target = target;
|
||||||
}
|
}
|
||||||
} else if (to && typeof to === 'object') {
|
|
||||||
el = RouterLink;
|
|
||||||
linkProps.target = target;
|
|
||||||
if (to.pathname.startsWith(`${window.Radarr.urlBase}/`)) {
|
|
||||||
linkProps.to = to;
|
|
||||||
} else {
|
|
||||||
const pathname = `${window.Radarr.urlBase}/${to.pathname.replace(/^\//, '')}`;
|
|
||||||
linkProps.to = {
|
|
||||||
...to,
|
|
||||||
pathname
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (el === 'button' || el === 'input') {
|
if (el === 'button' || el === 'input') {
|
||||||
@@ -95,7 +82,7 @@ class Link extends Component {
|
|||||||
Link.propTypes = {
|
Link.propTypes = {
|
||||||
className: PropTypes.string,
|
className: PropTypes.string,
|
||||||
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
component: PropTypes.oneOfType([PropTypes.string, PropTypes.func]),
|
||||||
to: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
|
to: PropTypes.string,
|
||||||
target: PropTypes.string,
|
target: PropTypes.string,
|
||||||
isDisabled: PropTypes.bool,
|
isDisabled: PropTypes.bool,
|
||||||
noRouter: PropTypes.bool,
|
noRouter: PropTypes.bool,
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
.loadingMessage {
|
.loadingMessage {
|
||||||
margin: 10px 10px 0;
|
margin: 50px 10px 0;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: 300;
|
font-weight: 300;
|
||||||
font-size: 36px;
|
font-size: 36px;
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ const messages = [
|
|||||||
'Hum something loud while others stare',
|
'Hum something loud while others stare',
|
||||||
'Loading humorous message... Please Wait',
|
'Loading humorous message... Please Wait',
|
||||||
'I could\'ve been faster in Python',
|
'I could\'ve been faster in Python',
|
||||||
'Don\'t forget to rewind your movies',
|
'Don\'t forget to rewind your tracks',
|
||||||
'Congratulations! you are the 1000th visitor.',
|
'Congratulations! you are the 1000th visitor.',
|
||||||
'HELP! I\'m being held hostage and forced to write these stupid lines!',
|
'HELP! I\'m being held hostage and forced to write these stupid lines!',
|
||||||
'RE-calibrating the internet...',
|
'RE-calibrating the internet...',
|
||||||
|
|||||||
@@ -30,10 +30,10 @@ function ConfirmModal(props) {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (isOpen) {
|
if (isOpen) {
|
||||||
bindShortcut('enter', onConfirm);
|
bindShortcut('enter', onConfirm);
|
||||||
|
} else {
|
||||||
return () => unbindShortcut('enter', onConfirm);
|
unbindShortcut('enter', onConfirm);
|
||||||
}
|
}
|
||||||
}, [isOpen, onConfirm]);
|
}, [onConfirm]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Modal
|
<Modal
|
||||||
|
|||||||
@@ -53,13 +53,7 @@ class PageHeader extends Component {
|
|||||||
return (
|
return (
|
||||||
<div className={styles.header}>
|
<div className={styles.header}>
|
||||||
<div className={styles.logoContainer}>
|
<div className={styles.logoContainer}>
|
||||||
<Link
|
<Link to={'/'}>
|
||||||
className={styles.logoLink}
|
|
||||||
to={{
|
|
||||||
pathname: '/',
|
|
||||||
state: { restoreScrollPosition: true }
|
|
||||||
}}
|
|
||||||
>
|
|
||||||
<img
|
<img
|
||||||
className={isSmallScreen ? styles.logo : styles.logoFull}
|
className={isSmallScreen ? styles.logo : styles.logoFull}
|
||||||
src={isSmallScreen ? `${window.Radarr.urlBase}/Content/Images/logo.png` : `${window.Radarr.urlBase}/Content/Images/logo-full.png`}
|
src={isSmallScreen ? `${window.Radarr.urlBase}/Content/Images/logo.png` : `${window.Radarr.urlBase}/Content/Images/logo-full.png`}
|
||||||
|
|||||||
@@ -1,11 +1,3 @@
|
|||||||
.page {
|
.page {
|
||||||
composes: page from '~./Page.css';
|
composes: page from '~./Page.css';
|
||||||
}
|
}
|
||||||
|
|
||||||
.logoFull {
|
|
||||||
margin-top: 50px;
|
|
||||||
margin-right: auto;
|
|
||||||
margin-left: auto;
|
|
||||||
width: 120px;
|
|
||||||
height: 40px;
|
|
||||||
}
|
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -61,8 +61,8 @@ const links = [
|
|||||||
to: '/activity/history'
|
to: '/activity/history'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
title: translate('Blocklist'),
|
title: translate('Blacklist'),
|
||||||
to: '/activity/blocklist'
|
to: '/activity/blacklist'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -10,7 +10,6 @@ import SpinnerIcon from 'Components/SpinnerIcon';
|
|||||||
import { forEach } from 'Helpers/elementChildren';
|
import { forEach } from 'Helpers/elementChildren';
|
||||||
import { align, icons } from 'Helpers/Props';
|
import { align, icons } from 'Helpers/Props';
|
||||||
import dimensions from 'Styles/Variables/dimensions';
|
import dimensions from 'Styles/Variables/dimensions';
|
||||||
import translate from 'Utilities/String/translate';
|
|
||||||
import styles from './PageToolbarSection.css';
|
import styles from './PageToolbarSection.css';
|
||||||
|
|
||||||
const BUTTON_WIDTH = parseInt(dimensions.toolbarButtonWidth);
|
const BUTTON_WIDTH = parseInt(dimensions.toolbarButtonWidth);
|
||||||
@@ -162,7 +161,7 @@ class PageToolbarSection extends Component {
|
|||||||
<ToolbarMenuButton
|
<ToolbarMenuButton
|
||||||
className={styles.overflowMenuButton}
|
className={styles.overflowMenuButton}
|
||||||
iconName={icons.OVERFLOW}
|
iconName={icons.OVERFLOW}
|
||||||
text={translate('More')}
|
text="More"
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<MenuContent>
|
<MenuContent>
|
||||||
|
|||||||
@@ -49,7 +49,7 @@
|
|||||||
background-color: $dangerColor;
|
background-color: $dangerColor;
|
||||||
|
|
||||||
&:global(.colorImpaired) {
|
&:global(.colorImpaired) {
|
||||||
background: repeating-linear-gradient(90deg, $dangerColor, $dangerColor 5px, $dangerColor 5px, $dimColor 10px);
|
background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@
|
|||||||
background-color: $warningColor;
|
background-color: $warningColor;
|
||||||
|
|
||||||
&:global(.colorImpaired) {
|
&:global(.colorImpaired) {
|
||||||
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, $warningColor 5px, $dimColor 10px);
|
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
.image {
|
|
||||||
align-content: center;
|
|
||||||
margin-right: 5px;
|
|
||||||
vertical-align: -0.125em;
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
import PropTypes from 'prop-types';
|
|
||||||
import React, { PureComponent } from 'react';
|
|
||||||
import styles from './RottenTomatoRating.css';
|
|
||||||
|
|
||||||
class RottenTomatoRating extends PureComponent {
|
|
||||||
|
|
||||||
//
|
|
||||||
// Render
|
|
||||||
|
|
||||||
render() {
|
|
||||||
|
|
||||||
const {
|
|
||||||
ratings,
|
|
||||||
hideIcon,
|
|
||||||
iconSize
|
|
||||||
} = this.props;
|
|
||||||
|
|
||||||
const rtRotten = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJNNDQ1LjE4NSA0NDQuNjg0Yy03OS4zNjkgNC4xNjctOTUuNTg3LTg2LjY1Mi0xMjYuNzI2LTg2LjAwNi0xMy4yNjguMjc5LTIzLjcyNiAxNC4xNTEtMTkuMTMzIDMwLjMyIDIuNTI1IDguODg4IDkuNTMgMjEuOTIzIDEzLjk0NCAzMC4wMTEgMTUuNTcgMjguNTQ0LTcuNDQ3IDYwLjg0NS0zNC4zODMgNjMuNTc3LTQ0Ljc2IDQuNTQtNjMuNDMzLTIxLjQyNi02Mi4yNzgtNDguMDA3IDEuMy0yOS44NCAyNi42LTYwLjMzMS42NS03My4zMDUtMjcuMTk0LTEzLjU5Ny00OS4zMDEgMzkuNTcyLTc1LjMyNSA1MS40MzktMjMuNTUzIDEwLjc0MS01Ni4yNDggMi40MTMtNjcuODcyLTIzLjc0MS04LjE2NC0xOC4zNzktNi42OC01My43NjggMjkuNjctNjcuMjcgMjIuNzA2LTguNDMzIDczLjMwNSAxMS4wMjkgNzUuOS0xMy42MjMgMi45OTItMjguNDE2LTUzLjE1NS0zMC44MTItNzAuMDYtMzcuNjI2LTI5LjkxMi0xMi4wNTUtNDcuNTY3LTM3Ljg1LTMzLjczNC02NS41MjIgMTAuMzc4LTIwLjc1NyA0MC45MTUtMjkuMjAzIDY0LjIyMy0yMC4xMSAyNy45MjIgMTAuODkyIDMyLjQwNCAzOS44NTMgNDYuNzEgNTEuODk3IDEyLjMyNCAxMC4zOCAyOS4xOSAxMS42OCA0MC4yMiA0LjU0MyA4LjEzNS01LjI2NSAxMC44NDMtMTYuODI4IDcuNzc0LTI3LjM5LTQuMDctMTQuMDIzLTE0Ljg3NS0yMi43NzMtMjUuNDE1LTMxLjM0Ni0xOC43NTgtMTUuMjQ5LTQ1LjI0LTI4LjM2LTI5LjIyMi02OS45ODMgMTMuMTMtMzQuMTEgNTEuNjQyLTM1LjM0IDUxLjY0Mi0zNS4zNCAxNS4zLTEuNzIgMjkuMDAyIDIuOSA0MC4xNjcgMTIuODc1IDE0LjkyNyAxMy4zMzUgMTcuODM0IDMxLjE2IDE1LjMzNiA1MC4xNzYtMi4yODMgMTcuMzU4LTguNDI2IDMyLjU2LTExLjYzIDQ5Ljc1OS0zLjcxNyAxOS45NjYgNi45NTQgNDAuMDg2IDI3LjI0OSA0MC44NjkgMjYuNjk0IDEuMDMxIDM0LjY5OC0xOS40ODYgMzcuOTY0LTMyLjQ5MiA0Ljc4Mi0xOS4wMjggMTEuMDU4LTM2LjY5NCAyOC43MTgtNDcuODIgMjUuMzQ2LTE1Ljk3IDYwLjU1Mi0xMi40NyA3Ni44ODYgMTguMjIyIDEyLjkyIDI0LjI4NCA4Ljc3MiA1Ny43MTUtMTEuMDQ3IDc1Ljk3LTguODkyIDguMTg4LTE5LjU4NCAxMS4wNzUtMzEuMTQ4IDExLjE1Ni0xNi41ODUuMTE3LTMzLjE2Mi0uMjktNDguNTU2IDcuNDcxLTEwLjQ4IDUuMjgxLTE1LjA0NyAxMy44ODgtMTUuMDQ1IDI1LjQyMyAwIDExLjI0MiA1Ljg1MyAxOC41ODUgMTUuMzM2IDIzLjM2MyAxNy44NiA5LjAwMyAzNy41NzcgMTAuODQzIDU2Ljg3MSAxNC4yMjIgMjcuOTggNC45IDUyLjU4MSAxNC43NTUgNjguMzc1IDQwLjcyLjE0Mi4yMjguMjguNDU4LjQxNS42OSAxOC4xMzkgMzAuNzQxLS44MzEgNzUuMDA1LTM2LjQ3NiA3Ni44NzgiIGZpbGw9IiMwQUM4NTUiLz48L3N2Zz4=';
|
|
||||||
const rtFresh = 'data:image/svg+xml;base64,PHN2ZyB2aWV3Qm94PSIwIDAgNTYwIDU2MCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNDc4LjI5IDI5Ni45OGMtMy45OS02My45NjYtMzYuNTItMTExLjgyLTg1LjQ2OC0xMzguNTggMC4yNzggMS41Ni0xLjEwOSAzLjUwOC0yLjY4OCAyLjgxOC0zMi4wMTYtMTQuMDA2LTg2LjMyOCAzMS4zMi0xMjQuMjggNy41ODQgMC4yODUgOC41MTktMS4zNzggNTAuMDcyLTU5LjkxNCA1Mi40ODMtMS4zODIgMC4wNTYtMi4xNDItMS4zNTUtMS4yNjgtMi4zNTQgNy44MjgtOC45MjkgMTUuNzMyLTMxLjUzNSA0LjM2Ny00My41ODYtMjQuMzM4IDIxLjgxLTM4LjQ3MiAzMC4wMTctODUuMTM4IDE5LjE4Ni0yOS44NzggMzEuMjQxLTQ2LjgwOSA3NC00My40ODUgMTI3LjI2IDYuNzggMTA4Ljc0IDEwOC42MyAxNzAuODkgMjExLjE5IDE2NC40OSAxMDIuNTYtNi4zOTUgMTkzLjQ3LTgwLjU3MiAxODYuNjgtMTg5LjMxIiBmaWxsPSIjRkEzMjBBIi8+PHBhdGggZD0iTTI5MS4zNzUgMTMyLjI5M2MyMS4wNzUtNS4wMjMgODEuNjkzLS40OSAxMDEuMTE0IDI1LjI3NCAxLjE2NiAxLjU0NS0uNDc1IDQuNDY4LTIuMzU1IDMuNjQ4LTMyLjAxNi0xNC4wMDYtODYuMzI4IDMxLjMyLTEyNC4yODIgNy41ODQuMjg1IDguNTE5LTEuMzc4IDUwLjA3Mi01OS45MTQgNTIuNDgzLTEuMzgyLjA1Ni0yLjE0Mi0xLjM1NS0xLjI2OC0yLjM1NCA3LjgyOC04LjkyOSAxNS43My0zMS41MzUgNC4zNjctNDMuNTg2LTI2LjUxMiAyMy43NTgtNDAuODg0IDMxLjM5Mi05OC40MjYgMTUuODM4LTEuODgzLS41MDgtMS4yNDEtMy41MzUuNzYyLTQuMjk4IDEwLjg3Ni00LjE1NyAzNS41MTUtMjIuMzYxIDU4LjgyNC0zMC4zODUgNC40MzgtMS41MjYgOC44NjItMi43MSAxMy4xOC0zLjQtMjUuNjY1LTIuMjkzLTM3LjIzNS01Ljg2Mi01My41NTktMy40LTEuNzg5LjI3LTMuMDA0LTEuODEzLTEuODk1LTMuMjQxIDIxLjk5NS0yOC4zMzIgNjIuNTEzLTM2Ljg4OCA4Ny41MTItMjEuODM3LTE1LjQxLTE5LjA5NC0yNy40OC0zNC4zMjEtMjcuNDgtMzQuMzIxbDI4LjYwMS0xNi4yNDZzMTEuODE3IDI2LjQgMjAuNDE0IDQ1LjYxNGMyMS4yNzUtMzEuNDM1IDYwLjg2LTM0LjMzNiA3Ny41ODUtMTIuMDMzLjk5MiAxLjMyNi0uMDQ1IDMuMjEtMS43MDIgMy4xNzEtMTMuNjEyLS4zMzEtMjEuMTA3IDEyLjA1LTIxLjY3NSAyMS40NjZsLjE5Ny4wMjMiIGZpbGw9IiMwMDkxMkQiLz48L3N2Zz4=';
|
|
||||||
|
|
||||||
const rating = ratings.rottenTomatoes;
|
|
||||||
|
|
||||||
let ratingString = '0%';
|
|
||||||
|
|
||||||
if (rating) {
|
|
||||||
ratingString = `${rating.value}%`;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<span>
|
|
||||||
{
|
|
||||||
!hideIcon &&
|
|
||||||
<img
|
|
||||||
className={styles.image}
|
|
||||||
src={rating.value > 50 ? rtFresh : rtRotten}
|
|
||||||
style={{
|
|
||||||
height: `${iconSize}px`
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
}
|
|
||||||
|
|
||||||
{ratingString}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
RottenTomatoRating.propTypes = {
|
|
||||||
ratings: PropTypes.object.isRequired,
|
|
||||||
iconSize: PropTypes.number.isRequired,
|
|
||||||
hideIcon: PropTypes.bool
|
|
||||||
};
|
|
||||||
|
|
||||||
RottenTomatoRating.defaultProps = {
|
|
||||||
iconSize: 14
|
|
||||||
};
|
|
||||||
|
|
||||||
export default RottenTomatoRating;
|
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { DndProvider } from 'react-dnd-multi-backend';
|
import { DndProvider } from 'react-dnd';
|
||||||
import HTML5toTouch from 'react-dnd-multi-backend/dist/esm/HTML5toTouch';
|
import { HTML5Backend } from 'react-dnd-html5-backend';
|
||||||
import Form from 'Components/Form/Form';
|
import Form from 'Components/Form/Form';
|
||||||
import FormGroup from 'Components/Form/FormGroup';
|
import FormGroup from 'Components/Form/FormGroup';
|
||||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||||
@@ -128,7 +128,7 @@ class TableOptionsModal extends Component {
|
|||||||
const isDraggingDown = isDragging && dropIndex > dragIndex;
|
const isDraggingDown = isDragging && dropIndex > dragIndex;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<DndProvider options={HTML5toTouch}>
|
<DndProvider backend={HTML5Backend}>
|
||||||
<Modal
|
<Modal
|
||||||
isOpen={isOpen}
|
isOpen={isOpen}
|
||||||
onModalClose={onModalClose}
|
onModalClose={onModalClose}
|
||||||
|
|||||||
@@ -39,8 +39,7 @@ class VirtualTable extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
width: 0,
|
width: 0
|
||||||
scrollRestored: false
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this._grid = null;
|
this._grid = null;
|
||||||
@@ -49,13 +48,11 @@ class VirtualTable extends Component {
|
|||||||
componentDidUpdate(prevProps, prevState) {
|
componentDidUpdate(prevProps, prevState) {
|
||||||
const {
|
const {
|
||||||
items,
|
items,
|
||||||
scrollIndex,
|
scrollIndex
|
||||||
scrollTop
|
|
||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
width,
|
width
|
||||||
scrollRestored
|
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
if (this._grid &&
|
if (this._grid &&
|
||||||
@@ -71,11 +68,6 @@ class VirtualTable extends Component {
|
|||||||
columnIndex: 0
|
columnIndex: 0
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this._grid && scrollTop !== undefined && scrollTop !== 0 && !scrollRestored) {
|
|
||||||
this.setState({ scrollRestored: true });
|
|
||||||
this._grid.scrollToPosition({ scrollTop });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
@@ -104,7 +96,6 @@ class VirtualTable extends Component {
|
|||||||
items,
|
items,
|
||||||
scroller,
|
scroller,
|
||||||
focusScroller,
|
focusScroller,
|
||||||
scrollTop: ignored,
|
|
||||||
header,
|
header,
|
||||||
headerHeight,
|
headerHeight,
|
||||||
rowRenderer,
|
rowRenderer,
|
||||||
@@ -189,7 +180,6 @@ VirtualTable.propTypes = {
|
|||||||
className: PropTypes.string.isRequired,
|
className: PropTypes.string.isRequired,
|
||||||
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
items: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||||
scrollIndex: PropTypes.number,
|
scrollIndex: PropTypes.number,
|
||||||
scrollTop: PropTypes.number,
|
|
||||||
scroller: PropTypes.instanceOf(Element).isRequired,
|
scroller: PropTypes.instanceOf(Element).isRequired,
|
||||||
focusScroller: PropTypes.bool.isRequired,
|
focusScroller: PropTypes.bool.isRequired,
|
||||||
header: PropTypes.node.isRequired,
|
header: PropTypes.node.isRequired,
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
.image {
|
|
||||||
align-content: center;
|
|
||||||
margin-right: 5px;
|
|
||||||
vertical-align: -0.125em;
|
|
||||||
}
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user