mirror of
https://github.com/Radarr/Radarr.git
synced 2026-03-11 15:20:34 -04:00
Compare commits
111 Commits
changelog-
...
v4.6.2.749
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e4429d2919 | ||
|
|
7052a7a5ec | ||
|
|
b38912851b | ||
|
|
1354c2c337 | ||
|
|
e259235df6 | ||
|
|
0cc1fe8308 | ||
|
|
f4fe18a440 | ||
|
|
eeed935e3a | ||
|
|
1b3701371a | ||
|
|
d56f3ec2e7 | ||
|
|
e7e3aac971 | ||
|
|
d2cb36c88a | ||
|
|
2fe28cb1dc | ||
|
|
5d65b4cae4 | ||
|
|
b0f56e2840 | ||
|
|
5593837482 | ||
|
|
8231290c7b | ||
|
|
0c1b88c60a | ||
|
|
0b8478e4a1 | ||
|
|
69e09c8687 | ||
|
|
3f2ea49023 | ||
|
|
32f09633e9 | ||
|
|
3542b263c7 | ||
|
|
d5cc84d8c8 | ||
|
|
c0790060fb | ||
|
|
5ec7e86488 | ||
|
|
b8abafd72f | ||
|
|
a471f1b44f | ||
|
|
7fe34be789 | ||
|
|
471a34eabf | ||
|
|
4fe5e5974e | ||
|
|
1ca66d0b29 | ||
|
|
4ab1cb393a | ||
|
|
fa1f07987c | ||
|
|
b5a5530cb1 | ||
|
|
e0448f7213 | ||
|
|
8eee5a3b1d | ||
|
|
830f1aa10f | ||
|
|
7666c7b1eb | ||
|
|
0b4c12dd7b | ||
|
|
53857083f2 | ||
|
|
ea9c77cf49 | ||
|
|
43ed8d0c2b | ||
|
|
9df06b80bf | ||
|
|
713f984b26 | ||
|
|
683d261a91 | ||
|
|
b33d9a9641 | ||
|
|
c69cc20266 | ||
|
|
4fc1ee0aff | ||
|
|
1d4b6d4cad | ||
|
|
5baeba18cb | ||
|
|
854b3045fe | ||
|
|
6b80c244bf | ||
|
|
044de922fa | ||
|
|
c987824174 | ||
|
|
8762588ef0 | ||
|
|
ed68a944ea | ||
|
|
52c64080f2 | ||
|
|
d878738a62 | ||
|
|
af496fe701 | ||
|
|
bbcd0b7861 | ||
|
|
1bf3302ec2 | ||
|
|
e55c3f7ddf | ||
|
|
4eb89eb851 | ||
|
|
71dfd897a8 | ||
|
|
a1ccfacfa2 | ||
|
|
29ba6fe556 | ||
|
|
7b7b866777 | ||
|
|
371eb68bf0 | ||
|
|
f8cb8c6bd8 | ||
|
|
488f8c71e8 | ||
|
|
c3cdb867a8 | ||
|
|
6163307c1c | ||
|
|
e9dcef34d4 | ||
|
|
b7be2c1d6e | ||
|
|
933c23ce57 | ||
|
|
aa794bddab | ||
|
|
d5605abd91 | ||
|
|
5ead395f9f | ||
|
|
0f34948c00 | ||
|
|
99d865ee4a | ||
|
|
90096451e0 | ||
|
|
84570159ae | ||
|
|
8d264020aa | ||
|
|
65850e6a5d | ||
|
|
db154ae9a4 | ||
|
|
df70d85d0a | ||
|
|
fa6804767c | ||
|
|
2e252771de | ||
|
|
fd76d67bae | ||
|
|
156def3138 | ||
|
|
9175c737d3 | ||
|
|
19a1f97be8 | ||
|
|
112550399b | ||
|
|
574d1c8d0f | ||
|
|
3feaee25e2 | ||
|
|
bb77538701 | ||
|
|
731db1ad79 | ||
|
|
fe76cbfc6b | ||
|
|
695cab3f3a | ||
|
|
e1d76689f7 | ||
|
|
24bd2ae59b | ||
|
|
42267da4ef | ||
|
|
a28b9ceff0 | ||
|
|
48b9bb9427 | ||
|
|
10bb8fa263 | ||
|
|
588c8fb074 | ||
|
|
f14482cb59 | ||
|
|
7ff48a197a | ||
|
|
84bf30dcda | ||
|
|
8b291d932f |
@@ -40,9 +40,18 @@ dotnet_naming_style.instance_field_style.capitalization = camel_case
|
||||
dotnet_naming_style.instance_field_style.required_prefix = _
|
||||
|
||||
# Prefer "var" everywhere
|
||||
csharp_style_var_for_built_in_types = true:suggestion
|
||||
csharp_style_var_when_type_is_apparent = true:suggestion
|
||||
csharp_style_var_elsewhere = true:suggestion
|
||||
csharp_style_var_for_built_in_types = true
|
||||
csharp_style_var_when_type_is_apparent = true
|
||||
csharp_style_var_elsewhere = true
|
||||
# Prefer "out" variables to be declared inline
|
||||
csharp_style_inlined_variable_declaration = true
|
||||
|
||||
# Using directive is unnecessary.
|
||||
dotnet_diagnostic.IDE0005.severity = error
|
||||
# Use var instead of explicit type
|
||||
dotnet_diagnostic.IDE0007.severity = error
|
||||
# Inline variable declaration
|
||||
dotnet_diagnostic.IDE0018.severity = error
|
||||
|
||||
# Stylecop Rules
|
||||
dotnet_diagnostic.SA0001.severity = none
|
||||
|
||||
2
.gitattributes
vendored
2
.gitattributes
vendored
@@ -3,7 +3,7 @@
|
||||
|
||||
# Explicitly set bash scripts to have unix endings
|
||||
*.sh text eol=lf
|
||||
macOS/Radarr text eol=lf
|
||||
distribution/osx/Radarr text eol=lf
|
||||
|
||||
# Custom for Visual Studio
|
||||
*.cs diff=csharp
|
||||
|
||||
@@ -9,7 +9,7 @@ variables:
|
||||
testsFolder: './_tests'
|
||||
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
|
||||
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
|
||||
majorVersion: '4.5.1'
|
||||
majorVersion: '4.6.2'
|
||||
minorVersion: $[counter('minorVersion', 2000)]
|
||||
radarrVersion: '$(majorVersion).$(minorVersion)'
|
||||
buildName: '$(Build.SourceBranchName).$(radarrVersion)'
|
||||
@@ -211,8 +211,8 @@ stages:
|
||||
displayName: Fetch Frontend
|
||||
- bash: |
|
||||
./build.sh --packages --installer
|
||||
cp setup/output/Radarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||
cp setup/output/Radarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||
cp distribution/windows/setup/output/Radarr.*win-x64.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x64-installer.exe
|
||||
cp distribution/windows/setup/output/Radarr.*win-x86.exe ${BUILD_ARTIFACTSTAGINGDIRECTORY}/Radarr.${BUILDNAME}.windows-core-x86-installer.exe
|
||||
displayName: Create Installers
|
||||
- publish: $(Build.ArtifactStagingDirectory)
|
||||
artifact: 'WindowsInstaller'
|
||||
|
||||
6
build.sh
6
build.sh
@@ -21,7 +21,7 @@ UpdateVersionNumber()
|
||||
echo "Updating Version Info"
|
||||
sed -i'' -e "s/<AssemblyVersion>[0-9.*]\+<\/AssemblyVersion>/<AssemblyVersion>$RADARRVERSION<\/AssemblyVersion>/g" src/Directory.Build.props
|
||||
sed -i'' -e "s/<AssemblyConfiguration>[\$()A-Za-z-]\+<\/AssemblyConfiguration>/<AssemblyConfiguration>${BUILD_SOURCEBRANCHNAME}<\/AssemblyConfiguration>/g" src/Directory.Build.props
|
||||
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$RADARRVERSION<\/string>/g" macOS/Radarr.app/Contents/Info.plist
|
||||
sed -i'' -e "s/<string>10.0.0.0<\/string>/<string>$RADARRVERSION<\/string>/g" distribution/osx/Radarr.app/Contents/Info.plist
|
||||
fi
|
||||
}
|
||||
|
||||
@@ -184,7 +184,7 @@ PackageMacOSApp()
|
||||
|
||||
rm -rf $folder
|
||||
mkdir -p $folder
|
||||
cp -r macOS/Radarr.app $folder
|
||||
cp -r distribution/osx/Radarr.app $folder
|
||||
mkdir -p $folder/Radarr.app/Contents/MacOS
|
||||
|
||||
echo "Copying Binaries"
|
||||
@@ -246,7 +246,7 @@ BuildInstaller()
|
||||
local framework="$1"
|
||||
local runtime="$2"
|
||||
|
||||
./_inno/ISCC.exe setup/radarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
|
||||
./_inno/ISCC.exe distribution/windows/setup/radarr.iss "//DFramework=$framework" "//DRuntime=$runtime"
|
||||
}
|
||||
|
||||
InstallInno()
|
||||
|
||||
@@ -1,100 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.0.5.5977 has been released on `develop`
|
||||
|
||||
A reminder about the `develop` branch
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first. This version will receive updates either weeklyish or bi-weeklyish depending on development.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- **Due to undocumented and breaking API changes Qbit v4.4.0 is not supported. It is generally recommended to avoid Qbit .0 releases.** Qbit v4.3.9 is the most recent working version. Qbit v4.4.1 may have issues as well.
|
||||
- **Radarr v4 no longer supports Linux x86 (x32 bit) systems**
|
||||
- x32 Arm is still supported; armv7 is the minimum required architecture
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr v4 no longer builds for mono and mono support has ceased**
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr Breaking API Changes**
|
||||
- Radarr v4 no longer supports the legacy (v0.2) API
|
||||
- Native ASPCore API Controllers (stricter typing and other small API changes)
|
||||
- The json you post needs to actually be strictly valid json now
|
||||
- **FFProbe has replaced MediaInfo**
|
||||
- Similarly MediaInfo is no longer a required dependency
|
||||
- [Jackett `/all` is deprecated and no longer supported. The FAQ has warned about this since May 2021.](https://wiki.servarr.com/radarr/faq#jacketts-all-endpoint)
|
||||
- Radarr is now on .Net6
|
||||
- New builds for OSX Arm64 and Linux Musl Arm32
|
||||
- IMDb Ratings
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Lidarr v1 coming to `develop` as beta soon^(tm)
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- [Radarr Postgres Database Support coming soon (PR#6873)](https://github.com/radarr/radarr/pull/6873)
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the SynoCommunity to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.0.5.5977 (changes since v4.0.4.5922)
|
||||
|
||||
- Update Synology error codes
|
||||
|
||||
- Fixed: Remove pre-DB from frontend storage
|
||||
|
||||
- Fixed: Removing multiple items from the queue wording
|
||||
|
||||
- Fixed: Improve help text for download client Category
|
||||
|
||||
- New: Update Cert Validation Help Text [common]
|
||||
|
||||
- Fixed: Updated ruTorrent stopped state helptext
|
||||
|
||||
- fixed text box not being uniform to others
|
||||
|
||||
- New: Add backup size information
|
||||
|
||||
- Fix swagger inCinema references
|
||||
|
||||
- Fixed: Recycle bin log message
|
||||
|
||||
- Fix nzbdrone reference
|
||||
|
||||
- additional testcase obfuscation
|
||||
|
||||
- Fixed: IPv4 instead of IP4
|
||||
|
||||
- Report runtime identifier to sentry
|
||||
|
||||
- Update API URL
|
||||
|
||||
- Fixed: No longer require first run as admin on windows
|
||||
|
||||
- Build installer from build.sh
|
||||
|
||||
- Fixed: Enable response compression over https
|
||||
|
||||
- Bump to 4.0.5
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,107 +0,0 @@
|
||||
# New Stable Release
|
||||
|
||||
Radarr v4.0.5.5981 has been released on `master`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` or beta `develop` testing branches should take advantage of this parity and switch to `master`
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first. This version will receive updates either weeklyish or bi-weeklyish depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : The bleeding edge. Released as soon as code is committed and passed all automated tests. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- **Due to undocumented and breaking API changes Qbit v4.4.0 is not supported. It is generally recommended to avoid Qbit .0 releases.** Qbit v4.3.9 is the most recent working version. Qbit v4.4.1 may have issues as well.
|
||||
- **Radarr v4 no longer supports Linux x86 (x32 bit) systems**
|
||||
- x32 Arm is still supported; armv7 is the minimum required architecture
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr v4 no longer builds for mono and mono support has ceased**
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr Breaking API Changes**
|
||||
- Radarr v4 no longer supports the legacy (v0.2) API
|
||||
- Native ASPCore API Controllers (stricter typing and other small API changes)
|
||||
- The json you post needs to actually be strictly valid json now
|
||||
- **FFProbe has replaced MediaInfo**
|
||||
- Similarly MediaInfo is no longer a required dependency
|
||||
- [Jackett `/all` is deprecated and no longer supported. The FAQ has warned about this since May 2021.](https://wiki.servarr.com/radarr/faq#jacketts-all-endpoint)
|
||||
- Radarr is now on .Net6
|
||||
- New builds for OSX Arm64 and Linux Musl Arm32
|
||||
- IMDb Ratings
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Lidarr v1 coming to `develop` as beta soon^(tm)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- [Radarr Postgres Database Support coming soon (PR#6873)](https://github.com/radarr/radarr/pull/6873)
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:release](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:latest](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.0.5.5981 (changes since v4.0.5.5977)
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
|
||||
## v4.0.5.5977 (changes since v4.0.4.5922)
|
||||
|
||||
- Update Synology error codes
|
||||
|
||||
- Fixed: Remove pre-DB from frontend storage
|
||||
|
||||
- Fixed: Removing multiple items from the queue wording
|
||||
|
||||
- Fixed: Improve help text for download client Category
|
||||
|
||||
- New: Update Cert Validation Help Text [common]
|
||||
|
||||
- Fixed: Updated ruTorrent stopped state helptext
|
||||
|
||||
- fixed text box not being uniform to others
|
||||
|
||||
- New: Add backup size information
|
||||
|
||||
- Fix swagger inCinema references
|
||||
|
||||
- Fixed: Recycle bin log message
|
||||
|
||||
- Fix nzbdrone reference
|
||||
|
||||
- additional testcase obfuscation
|
||||
|
||||
- Fixed: IPv4 instead of IP4
|
||||
|
||||
- Report runtime identifier to sentry
|
||||
|
||||
- Update API URL
|
||||
|
||||
- Fixed: No longer require first run as admin on windows
|
||||
|
||||
- Build installer from build.sh
|
||||
|
||||
- Fixed: Enable response compression over https
|
||||
|
||||
- Bump to 4.0.5
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,180 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.1.0.6095 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first. This version will receive updates either weeklyish or bi-weeklyish depending on development.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- **Due to undocumented and breaking API changes Qbit v4.4.0 is not supported. It is generally recommended to avoid Qbit .0 releases.** Qbit v4.3.9 is the most recent working version. Qbit v4.4.1 has issues as well.
|
||||
- **Radarr v4 no longer supports Linux x86 (x32 bit) systems**
|
||||
- x32 Arm is still supported; armv7 is the minimum required architecture
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr v4 no longer builds for mono and mono support has ceased**
|
||||
- Impacted users have been receiving a healthcheck since May 2021 with 3.2.0
|
||||
- **Radarr Breaking API Changes**
|
||||
- Radarr v4 no longer supports the legacy (v0.2) API
|
||||
- Native ASPCore API Controllers (stricter typing and other small API changes)
|
||||
- The json you post needs to actually be strictly valid json now
|
||||
- **FFProbe has replaced MediaInfo**
|
||||
- Similarly MediaInfo is no longer a required dependency
|
||||
- [Jackett `/all` is deprecated and no longer supported. The FAQ has warned about this since May 2021.](https://wiki.servarr.com/radarr/faq#jacketts-all-endpoint)
|
||||
- Radarr is now on .Net6
|
||||
- New builds for OSX Arm64 and Linux Musl Arm32
|
||||
- IMDb Ratings
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Lidarr v1 coming to `develop` as beta soon^(tm)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- [Radarr Postgres Database Support coming soon (PR#6873)](https://github.com/radarr/radarr/pull/6873)
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.1.0.6095 (changes since v4.0.5.5981)
|
||||
|
||||
- Fixed: Validation when testing indexers, import lists, connections and download clients
|
||||
|
||||
- New: Added UDP syslog support
|
||||
|
||||
- Add error handling to Notifiarr connect to reduce Sentry hits
|
||||
|
||||
- Update multi parser test
|
||||
|
||||
- Remove old Multi language workaround
|
||||
|
||||
- Add response size to http responses
|
||||
|
||||
- Linting fixes for frontend following eslint package upgrade
|
||||
|
||||
- FontAwesome 6
|
||||
|
||||
- Bump react-text-truncate to 0.18.0
|
||||
|
||||
- Bump qs to 6.10.3
|
||||
|
||||
- Bump clipboard.js to 2.0.10
|
||||
|
||||
- Change react-custom-scrollbars to react-custom-scrollbars-2
|
||||
|
||||
- Update frontend babel packages
|
||||
|
||||
- Update frontend stylelint packages
|
||||
|
||||
- Update frontend eslint packages
|
||||
|
||||
- Bump Sentry to 3.15.0
|
||||
|
||||
- Bump NLog to 4.7.14
|
||||
|
||||
- Bump FluentMigrator to 3.3.2
|
||||
|
||||
- Bump dotnet to 6.0.3
|
||||
|
||||
- Bump DryIoc to 4.8.8
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified)) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Allow more startup time for openapi generation
|
||||
|
||||
- Bump Swashbuckle to 6.3.0
|
||||
|
||||
- Removed non-functional altyear API controller
|
||||
|
||||
- Update API docs
|
||||
|
||||
- API is v3
|
||||
|
||||
- Fix Prowlarr references
|
||||
|
||||
- Autogenerated API docs
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Translated using Weblate (French) [skip ci]
|
||||
|
||||
- New: Language filter on manual search
|
||||
|
||||
- Fix HistorySpecification tests
|
||||
|
||||
- New: Original Language and Title sort and filter options
|
||||
|
||||
- Fixed: Clearing logs not updating UI once complete
|
||||
|
||||
- Fixed: On Import notifications for webhooks
|
||||
|
||||
- Fixed: Send download client name instead of type for grab events
|
||||
|
||||
- New: Add qBittorrent sequential order and first and last piece priority options
|
||||
|
||||
- Fixed: Profiles with upgrades disabled incorrectly allowing upgrades in some cases
|
||||
|
||||
- New: Add Release group to history for all events
|
||||
|
||||
- Bump FFProbe to 5.0
|
||||
|
||||
- Fixed: Parsing of quality in DP.WEB releases
|
||||
|
||||
- Fixed: Correctly Detect Remux prefixed by Brackets
|
||||
|
||||
- Fixed: Treat 720p BR Remux as BluRay
|
||||
|
||||
- Fixed: Better Cleansing of Tracker Announce Keys
|
||||
|
||||
- New: Dont parse hash as release group
|
||||
|
||||
- New: Support for parsing various Anime Groups
|
||||
|
||||
- Fixed: Dont Parse HDRip as group
|
||||
|
||||
- New: Support for parsing [HDO] as HDO Group
|
||||
|
||||
- Fixed: Updater version number logging
|
||||
|
||||
- Adjusted the Windows LongPath support check for valid segment lengths
|
||||
|
||||
- PWA missing name
|
||||
|
||||
- Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]
|
||||
|
||||
- SimpleTitleRegex catchup
|
||||
|
||||
- Fixed: Assume SABnzbd develop version is 3.0.0 if not specified
|
||||
|
||||
- Bump node build version to 16.X LTS
|
||||
|
||||
- Bump dotnet to 6.0.2
|
||||
|
||||
- Bump version to 4.1.0
|
||||
|
||||
- Fixed: Update from version in logs
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,68 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.1.0.6122 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support has landed in `nightly` and will be coming to `develop` _soon_
|
||||
- Radarr Plex Watchlist Support has landed in `nightly` and will be coming to `develop` _soon_
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Lidarr v1 coming to `develop` as beta soon^(tm)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.1.0.6122 (changes since v4.1.0.6095)
|
||||
|
||||
- Fixed: Loading old commands from database
|
||||
|
||||
- Fixed: Scrolling in Firefox in small window (requires refresh)
|
||||
|
||||
- Don't return early after re-running checks after startup grace period
|
||||
|
||||
- Fixed: Delay health check notifications on startup
|
||||
|
||||
- New: Schedule refresh and process monitored download tasks at high priority
|
||||
|
||||
- Fixed: Use Digital Release in ChangeFileDate if no Physical
|
||||
|
||||
- Fixed: Cleanup Temp files after backup creation
|
||||
|
||||
- Centralise image choice, update to latest images
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,198 +0,0 @@
|
||||
# New Stable Release
|
||||
|
||||
Radarr v4.1.0.6175 has been released on `master`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` or beta `develop` testing branches should take advantage of this parity and switch to `master`
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support has landed in `nightly` and will be coming to `develop` _soon_
|
||||
- Radarr Plex Watchlist Support has landed in `nightly` and will be coming to `develop` _soon_
|
||||
- "FFMpeg 5.0.1" fixes issues with FFprobe crashing on macOS
|
||||
- Radarr improved collections support coming _soon_^(tm)
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Lidarr v1 coming to `develop` as beta soon^(tm)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:release](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:latest](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.1.0.6175 (changes since v4.1.0.6122)
|
||||
|
||||
- FFMpeg 5.0.1
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
|
||||
## v4.1.0.6122 (changes since v4.1.0.6095)
|
||||
|
||||
- Fixed: Loading old commands from database
|
||||
|
||||
- Fixed: Scrolling in Firefox in small window (requires refresh)
|
||||
|
||||
- Don't return early after re-running checks after startup grace period
|
||||
|
||||
- Fixed: Delay health check notifications on startup
|
||||
|
||||
- New: Schedule refresh and process monitored download tasks at high priority
|
||||
|
||||
- Fixed: Use Digital Release in ChangeFileDate if no Physical
|
||||
|
||||
- Fixed: Cleanup Temp files after backup creation
|
||||
|
||||
- Centralise image choice, update to latest images
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
|
||||
## v4.1.0.6095 (changes since v4.0.5.5981)
|
||||
|
||||
- Fixed: Validation when testing indexers, import lists, connections and download clients
|
||||
|
||||
- New: Added UDP syslog support
|
||||
|
||||
- Add error handling to Notifiarr connect to reduce Sentry hits
|
||||
|
||||
- Update multi parser test
|
||||
|
||||
- Remove old Multi language workaround
|
||||
|
||||
- Add response size to http responses
|
||||
|
||||
- Linting fixes for frontend following eslint package upgrade
|
||||
|
||||
- FontAwesome 6
|
||||
|
||||
- Bump react-text-truncate to 0.18.0
|
||||
|
||||
- Bump qs to 6.10.3
|
||||
|
||||
- Bump clipboard.js to 2.0.10
|
||||
|
||||
- Change react-custom-scrollbars to react-custom-scrollbars-2
|
||||
|
||||
- Update frontend babel packages
|
||||
|
||||
- Update frontend stylelint packages
|
||||
|
||||
- Update frontend eslint packages
|
||||
|
||||
- Bump Sentry to 3.15.0
|
||||
|
||||
- Bump NLog to 4.7.14
|
||||
|
||||
- Bump FluentMigrator to 3.3.2
|
||||
|
||||
- Bump dotnet to 6.0.3
|
||||
|
||||
- Bump DryIoc to 4.8.8
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified)) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Allow more startup time for openapi generation
|
||||
|
||||
- Bump Swashbuckle to 6.3.0
|
||||
|
||||
- Removed non-functional altyear API controller
|
||||
|
||||
- Update API docs
|
||||
|
||||
- API is v3
|
||||
|
||||
- Fix Prowlarr references
|
||||
|
||||
- Autogenerated API docs
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Translated using Weblate (French) [skip ci]
|
||||
|
||||
- New: Language filter on manual search
|
||||
|
||||
- Fix HistorySpecification tests
|
||||
|
||||
- New: Original Language and Title sort and filter options
|
||||
|
||||
- Fixed: Clearing logs not updating UI once complete
|
||||
|
||||
- Fixed: On Import notifications for webhooks
|
||||
|
||||
- Fixed: Send download client name instead of type for grab events
|
||||
|
||||
- New: Add qBittorrent sequential order and first and last piece priority options
|
||||
|
||||
- Fixed: Profiles with upgrades disabled incorrectly allowing upgrades in some cases
|
||||
|
||||
- New: Add Release group to history for all events
|
||||
|
||||
- Bump FFProbe to 5.0
|
||||
|
||||
- Fixed: Parsing of quality in DP.WEB releases
|
||||
|
||||
- Fixed: Correctly Detect Remux prefixed by Brackets
|
||||
|
||||
- Fixed: Treat 720p BR Remux as BluRay
|
||||
|
||||
- Fixed: Better Cleansing of Tracker Announce Keys
|
||||
|
||||
- New: Dont parse hash as release group
|
||||
|
||||
- New: Support for parsing various Anime Groups
|
||||
|
||||
- Fixed: Dont Parse HDRip as group
|
||||
|
||||
- New: Support for parsing [HDO] as HDO Group
|
||||
|
||||
- Fixed: Updater version number logging
|
||||
|
||||
- Adjusted the Windows LongPath support check for valid segment lengths
|
||||
|
||||
- PWA missing name
|
||||
|
||||
- Translated using Weblate (Chinese (Traditional) (zh_TW)) [skip ci]
|
||||
|
||||
- SimpleTitleRegex catchup
|
||||
|
||||
- Fixed: Assume SABnzbd develop version is 3.0.0 if not specified
|
||||
|
||||
- Bump node build version to 16.X LTS
|
||||
|
||||
- Bump dotnet to 6.0.2
|
||||
|
||||
- Bump version to 4.1.0
|
||||
|
||||
- Fixed: Update from version in logs
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,324 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.2.0.6438 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support
|
||||
- Radarr Plex Watchlist Support
|
||||
- Radarr Collections Support
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- [Lidarr v1 released on `master`](https://www.reddit.com/r/Lidarr/comments/v5fdhi/new_stable_release_master_v1022592/)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- Radarr Postgres Database Support in `nightly` and `develop`
|
||||
- Prowlarr Postgres Database Support in `nightly` and `develop`
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
- \*Arrs Wiki Contributions welcomed and strongly encouraged, simply auth with GitHub on the wiki and update the page
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.2.0.6438 (changes since v4.1.0.6175)
|
||||
|
||||
- Fixed: Parse Group ZØNEHD
|
||||
|
||||
- New: Parse Group HONE
|
||||
|
||||
- New: (Discord) Include Custom Formats & Score On Grab
|
||||
|
||||
- Translated using Weblate (Catalan) [skip ci]
|
||||
|
||||
- Fixed: User Triggered Auto Searches now ignores monitored status (#7422)
|
||||
|
||||
- Fixed: Postgres timezone issues (#7183)
|
||||
|
||||
- Speed up and reduce meta calls for Imdb Lists when mapping
|
||||
|
||||
- Fixed: ImportListMovies not saved if from a list without TMDBIds
|
||||
|
||||
- Match 'HQCAM' as CAM source (#7412)
|
||||
|
||||
- Fix RefreshMovieServiceFixture folder service mock
|
||||
|
||||
- Fixed: Collections not deleted on Movie Delete
|
||||
|
||||
- Fixed: Bulk Collection RootFolder change failure
|
||||
|
||||
- New: Collection Folder, Genre, QualityProfile Filters
|
||||
|
||||
- Fixed: Trim RootFolderPath on Migration
|
||||
|
||||
- Avoid multiple metadata DB calls on list mapping
|
||||
|
||||
- Fixed: Prevent excluded movies from being added by collections
|
||||
|
||||
- Fixed: Avoid NullRef in MapMovieToTmdbMovie
|
||||
|
||||
- Fixed: Notifiarr - Better HTTP Error Handling
|
||||
|
||||
- Fix Nullref on Collection delete
|
||||
|
||||
- New: (Notifiarr) Custom Formats in OnGrab
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Custom Format Spec Validation
|
||||
|
||||
- Fixed: Don't fail on single failure for Discover bulk add
|
||||
|
||||
- Remove general yarn restore key to avoid cross OS conflict
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Fixed: Don't call for server notifications on event driven check
|
||||
|
||||
- Rename MovieImportedEvent to MovieFileImportedEvent
|
||||
|
||||
- Fixed: Improved parsing WebDL Releases
|
||||
|
||||
- New: adding a link to tmdb in the import combobox movie search results (#7352)
|
||||
|
||||
- Fixed: Housekeeper doesn't remove collections that have MovieMeta from lists
|
||||
|
||||
- Fixed: Notify on Bulk Adds (Lists, Collections, Imports)
|
||||
|
||||
- Updated NLog Version (#7365)
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Fixed: Migration 208 fails when collection doesn't have name
|
||||
|
||||
- Fixed: Don't call AddMovies if no movies to add from Collection
|
||||
|
||||
- New: Default to IMDb Ratings in Kodi Metadata
|
||||
|
||||
- Translated using Weblate (Slovak) [skip ci]
|
||||
|
||||
- New: Separate Ratings Columns
|
||||
|
||||
- Fixed: Add support for more Anime release formats
|
||||
|
||||
- Translated using Weblate (Portuguese) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Bulk Edit Collections Profile, Root, Availability
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Fixed: Collections Improvements
|
||||
|
||||
- Add back Movie Credits and Alt Titles Indexes
|
||||
|
||||
- Fixed: Validate if equals or child for startup folder
|
||||
|
||||
- New: Notifiarr include Media Info in Download Notifications
|
||||
|
||||
- New: Notifiarr moved from webhook to API
|
||||
|
||||
- Translated using Weblate (German) [skip ci]
|
||||
|
||||
- Use DryIoc for Automoqer, drop Unity dependency
|
||||
|
||||
- Additional logging for partial Plex path scan
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Fixed: Improved empty root folder failsafe logging (#7341)
|
||||
|
||||
- Fixed: Register PostgresOptions when running in utility mode
|
||||
|
||||
- Fixed: Clarified genre filtering helptext on Trakt lists
|
||||
|
||||
- Fixed: Lithuanian media info parsing
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Fixed: MovieAdded trigger not available in UI
|
||||
|
||||
- New: Movie Added Notification
|
||||
|
||||
- Cleanup Collections UI Options
|
||||
|
||||
- Fixed: Speed up Collections API Endpoint
|
||||
|
||||
- New: Add DB Indexes for MovieMetadata
|
||||
|
||||
- New: .NET 6.0.5
|
||||
|
||||
- Translated using Weblate (Polish) [skip ci]
|
||||
|
||||
- Fixed: Remove Collection on last Movie delete
|
||||
|
||||
- Fixed: Correctly use loadash in FE Migrations
|
||||
|
||||
- Fixed: Partial Revert CF Validation for more robust solution
|
||||
|
||||
- Ensure .Mono and .Windows projects have all dependencies in build output
|
||||
|
||||
- Fix frontend monitor migration
|
||||
|
||||
- Try to fix CF null error for imported movie files
|
||||
|
||||
- Tweak monitor migration to avoid overwrites of valid settings
|
||||
|
||||
- Fixed: Run Frontend Migration for MonitorType
|
||||
|
||||
- New: Improve validation errors for Custom Formats
|
||||
|
||||
- Fixed: Don't Import Files with lower CF Score
|
||||
|
||||
- Fixed: Parse UHD2BD as BluRay instead of HDTV
|
||||
|
||||
- Fixed: Bluray 576p parsing
|
||||
|
||||
- New: Release Group Custom Format (#7154)
|
||||
|
||||
- Added term "brazilian" to Brazilian Portuguese parsing (#7296)
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Don't default manual import to move
|
||||
|
||||
- Fixed: Cutoff Unmet showing items above lowest accepted quality when upgrades are disabled
|
||||
|
||||
- New: Collections View
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- New: Parse QxR Group r00t
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Instance name in System/Status API endpoint
|
||||
|
||||
- New: Instance name for Page Title
|
||||
|
||||
- New: Instance Name used for Syslog
|
||||
|
||||
- New: Set Instance Name
|
||||
|
||||
- New: Add optional Source Title column to history
|
||||
|
||||
- New: Support for new Nyaa RSS Feed format
|
||||
|
||||
- Fixed: Don't try to add MovieMeta if mapping fails for list items
|
||||
|
||||
- Fixed: Importing file from UNC shared folder without job folder
|
||||
|
||||
- Fixed: No restart requirement for Refresh Monitored interval change
|
||||
|
||||
- Fixed: Correct User-Agent api logging
|
||||
|
||||
- Delete nan.json
|
||||
|
||||
- Delete zh_Hans.json
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified)) [skip ci]
|
||||
|
||||
- Fixed: Wrong translation mapping can be used for file naming and metadata
|
||||
|
||||
- Fixed: Translated fields are mapped incorrectly for existing search results
|
||||
|
||||
- Fixed: UI hiding search results with duplicate GUIDs
|
||||
|
||||
- Fixed: QBittorrent unknown download state: forcedMetaDL
|
||||
|
||||
- Fix migration 207 distinct on tmdbid only for list movie insert
|
||||
|
||||
- Fix metadata migration
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Rework Movie Metadata data model
|
||||
|
||||
- Temporarily ignore update tests until linux-x86 released
|
||||
|
||||
- New: Add linux-x86 builds
|
||||
|
||||
- New: Support Plex API Path Scan (Similar to autoscan)
|
||||
|
||||
- Fixed: Interactive Search Filter not filtering multiple qualities in the same filter row
|
||||
|
||||
- Added padding to search tab to maintain visual consistancy
|
||||
|
||||
- Fixed: Update ScheduledTask cache LastStartTime on command execution
|
||||
|
||||
- Bump Version to 4.2
|
||||
|
||||
- Bump webpack packages
|
||||
|
||||
- Remove old DotNetVersion method and dep
|
||||
|
||||
- Bump Monotorrent to 2.0.5
|
||||
|
||||
- Fixed: Don't die if Plex watchlist guid node is missing or null
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Add support for Plex Watchlist importing (#5707)
|
||||
|
||||
- New: Add date picker for custom filter dates
|
||||
|
||||
- Make postgres integration tests actually use postgres
|
||||
|
||||
- Fixed: Clarify Qbit Content Path Error
|
||||
|
||||
- Fixed: Use Movie Original Language for Custom Format Original Language (#6882)
|
||||
|
||||
- Fix .editorconfig to disallow `this`
|
||||
|
||||
- FFMpeg 5.0.1
|
||||
|
||||
- Fixed: Properly handle 119 error code from Synology Download Station
|
||||
|
||||
- Translated using Weblate (Hungarian) [skip ci]
|
||||
|
||||
- Fixed: FFprobe failing on MacOS and AV1 streams
|
||||
|
||||
- add 576 resolution back to simple title regex
|
||||
|
||||
- Translated using Weblate (Ukrainian) [skip ci]
|
||||
|
||||
- Set up tests on postgres
|
||||
|
||||
- Allow configuring postgres with environment variables
|
||||
|
||||
- New: Postgres Support
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,100 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.2.1.6478 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support
|
||||
- Radarr Plex Watchlist Support
|
||||
- Radarr Collections Support
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- [Lidarr v1 released on `master`](https://www.reddit.com/r/Lidarr/comments/v5fdhi/new_stable_release_master_v1022592/)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- Radarr Postgres Database Support in `nightly` and `develop`
|
||||
- Prowlarr Postgres Database Support in `nightly` and `develop`
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
- \*Arrs Wiki Contributions welcomed and strongly encouraged, simply auth with GitHub on the wiki and update the page
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.2.1.6478 (changes since [v4.2.0.6438](https://www.reddit.com/r/radarr/comments/w3kik4/new_release_develop_v4206438/))
|
||||
|
||||
- Translated using Weblate (Spanish) [skip ci]
|
||||
|
||||
- Regenerate yarn.lock
|
||||
|
||||
- Bump Sentry to 3.20.1
|
||||
|
||||
- Bump dotnet to 6.0.8
|
||||
|
||||
- Changed: Removed Tigole from ExceptionRelease match as is checked in ExceptionReleaseExact.
|
||||
|
||||
- Fixed: Tigole release group not being parsed and matched correctly, requiring manual import.
|
||||
|
||||
- Fixed: Configured recycle bin is excluded from import.
|
||||
|
||||
- Really fix Original Language in Language CF Specification
|
||||
|
||||
- Better Sentry Filtering for AggregateException children
|
||||
|
||||
- Run Postgres tests on 20.04
|
||||
|
||||
- Fixed: Blank Collection on MovieDetails when no Collection for Movie
|
||||
|
||||
- Remove non-functional filters for Trakt Lists
|
||||
|
||||
- Fixed: Original CF shouldn't need to be named "Original"
|
||||
|
||||
- Fixed NullRef in Skyhook Proxy during List Sync
|
||||
|
||||
- Fixed: Remove Notifiarr Environment Option
|
||||
|
||||
- Fixed: Trakt list request now uses correct rules for generating slug (#7449)
|
||||
|
||||
- Fixed: Allow blank ReleaseGroup and Edition from MovieFile edit
|
||||
|
||||
- Fixed: Don't process files that don't have a supported media file extension
|
||||
|
||||
- Fixed: Avoid failure if list contains same movie but without tmdbid
|
||||
|
||||
- Fixed: Log correct path when moving movies (#7439)
|
||||
|
||||
- Fixed: Watch state not preserved on metadata rewrite (#7436)
|
||||
|
||||
- Fixed: NullRefException in TorrentRssParser
|
||||
|
||||
- Bump Version to 4.2.1
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,78 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.2.2.6503 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support
|
||||
- Radarr Plex Watchlist Support
|
||||
- Radarr Collections Support
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- [Lidarr v1 released on `master`](https://www.reddit.com/r/Lidarr/comments/v5fdhi/new_stable_release_master_v1022592/)
|
||||
- [Lidarr](https://lidarr.audio/donate), [Prowlarr](https://prowlarr.com/donate), [Radarr](https://radarr.video/donate), [Readarr](https://readarr.com/donate) now accept direct bitcoin donations
|
||||
- [Readarr official beta on `develop` announced](https://www.reddit.com/r/Readarr/comments/sxvj8y/new_beta_release_develop_v0101248/)
|
||||
- Radarr Postgres Database Support in `nightly` and `develop`
|
||||
- Prowlarr Postgres Database Support in `nightly` and `develop`
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
- \*Arrs Wiki Contributions welcomed and strongly encouraged, simply auth with GitHub on the wiki and update the page
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.2.2.6503 (changes since [v4.2.1.6478](https://www.reddit.com/r/radarr/comments/woe62q/new_release_develop_v4216478/))
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: (API) Get Collection by TmdbId
|
||||
|
||||
- Added: Ntfy provider for notifications. (#7455)
|
||||
|
||||
- Fixed: Postgres secret regex now less greedy
|
||||
|
||||
- Fixed: Regex in log cleanser taking 10+ minutes on messages longer than 100k. (#7481)
|
||||
|
||||
- New: Add support for Plex Edition tags in naming
|
||||
|
||||
- New: Make Plex imdb tags conditional
|
||||
|
||||
- Fixed: Correctly map movie by original title on import
|
||||
|
||||
- Fixed: UI Error on Collection Filter
|
||||
|
||||
- Fixed: Allow 0 Min on Size CustomFormat Condition
|
||||
|
||||
- New: Add Slovak Language
|
||||
|
||||
- Bump version to 4.2.2
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,478 +0,0 @@
|
||||
# New Stable Release
|
||||
|
||||
Radarr v4.2.4.6635 has been released on `master`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` or beta `develop` testing branches should take advantage of this parity and switch to `master`
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Postgres Database Support
|
||||
- Radarr Plex Watchlist Support
|
||||
- Radarr Collections Support
|
||||
- Existing Collection Lists have been migrated
|
||||
- Some users may experience `Database Malformed` or other migration errors
|
||||
- This is caused by the database having existing corruption.
|
||||
- The solution is to follow the instructions noted on the FAQ for a malformed database. <https://wiki.servarr.com/radarr/faq#i-am-getting-an-error-database-disk-image-is-malformed>
|
||||
- Given this just occurred after an update then if the post-migrated database will not open or cannot be recovered then make a copy of the database from a recent backup and apply the database recovery process to that file then try starting Radarr with the recovered backup file. It should then migrate without issues then.
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
- Radarr Postgres Database Support in `master`
|
||||
- Prowlarr Postgres Database Support in `nightly` and `develop`
|
||||
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
|
||||
- \*Arrs Wiki Contributions welcomed and strongly encouraged, simply auth with GitHub on the wiki and update the page
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:release](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:latest](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.2.4.6635 (changes since v4.1.0.6175)
|
||||
|
||||
- Ignore SQLiteException tests on Azure
|
||||
|
||||
- Correct SQLiteException Sentry filtering
|
||||
|
||||
- Fix TagDetails sql for PG, add test
|
||||
|
||||
- Fixed: Add YTS.AG to the exception Release Groups (#7627)
|
||||
|
||||
- Fixed: Improve RarBG Error Handling
|
||||
|
||||
- fix typo in MovieRepository
|
||||
|
||||
- Fixed: Repack Preference Ignored
|
||||
|
||||
- Fixed: Ignore Movies with null tags when pulling AllMovieTags
|
||||
|
||||
- New: Torrent Seed Ratio no longer advance settings
|
||||
|
||||
- Translated using Weblate (Dutch) [skip ci]
|
||||
|
||||
- Remove unused package 'react-slick'
|
||||
|
||||
- Fixed: Collection Carousel Improvements
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Clarify Folder as Root Folder (#7598)
|
||||
|
||||
- Fixed: Toolbar Button labels overlap
|
||||
|
||||
- Fixed: Series list jump bar click issues
|
||||
|
||||
- Fixed: Use translated title for sorttitle in Kodi nfo
|
||||
|
||||
- Handle redirects for 308 redirects
|
||||
|
||||
- Fixed: Improve Radarr List help text
|
||||
|
||||
- Fixed: Improve Quality Profile in-use helptext
|
||||
|
||||
- Bump version to 4.2.4
|
||||
|
||||
- FileNameBuilderFixture tests should run on Windows
|
||||
|
||||
- New: Add Latvian language
|
||||
|
||||
- Fixed: Defaults for Trakt Popular List
|
||||
|
||||
- Fixed: Strip additional domains out of release prefix
|
||||
|
||||
- Fixed: Collections not sorting properly on Index
|
||||
|
||||
- Update Bug Report Template
|
||||
|
||||
- Update Bug Report Template [skip ci] [common]
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Fix: Trace logging postgres cleanse for large json files.
|
||||
|
||||
- Update src/NzbDrone.Core/CustomFormats/Specifications/RegexSpecificationBase.cs
|
||||
|
||||
- New: (UI) Indicate Custom Formats are Case Insensitive
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Add application URL to host configuration settings
|
||||
|
||||
- New: Setting to add Collection to NFO files
|
||||
|
||||
- Really fix UI Error on Collection Filter
|
||||
|
||||
- New: Preserve language tags when importing subtitle files
|
||||
|
||||
- Fixed: Skip extras in 'Extras' subfolder
|
||||
|
||||
- New: Import subtitles from sub folders
|
||||
|
||||
- Bump version to 4.2.3
|
||||
|
||||
- Translated using Weblate (German) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: (API) Get Collection by TmdbId
|
||||
|
||||
- Added: Ntfy provider for notifications. (#7455)
|
||||
|
||||
- Fixed: Postgres secret regex now less greedy
|
||||
|
||||
- Fixed: Regex in log cleanser taking 10+ minutes on messages longer than 100k. (#7481)
|
||||
|
||||
- New: Add support for Plex Edition tags in naming
|
||||
|
||||
- New: Make Plex imdb tags conditional
|
||||
|
||||
- Fixed: Correctly map movie by original title on import
|
||||
|
||||
- Fixed: UI Error on Collection Filter
|
||||
|
||||
- Fixed: Allow 0 Min on Size CustomFormat Condition
|
||||
|
||||
- New: Add Slovak Language
|
||||
|
||||
- Bump version to 4.2.2
|
||||
|
||||
- Translated using Weblate (Spanish) [skip ci]
|
||||
|
||||
- Regenerate yarn.lock
|
||||
|
||||
- Bump Sentry to 3.20.1
|
||||
|
||||
- Bump dotnet to 6.0.8
|
||||
|
||||
- Changed: Removed Tigole from ExceptionRelease match as is checked in ExceptionReleaseExact.
|
||||
|
||||
- Fixed: Tigole release group not being parsed and matched correctly, requiring manual import.
|
||||
|
||||
- Fixed: Configured recycle bin is excluded from import.
|
||||
|
||||
- Really fix Original Language in Language CF Specification
|
||||
|
||||
- Better Sentry Filtering for AggregateException children
|
||||
|
||||
- Run Postgres tests on 20.04
|
||||
|
||||
- Fixed: Blank Collection on MovieDetails when no Collection for Movie
|
||||
|
||||
- Remove non-functional filters for Trakt Lists
|
||||
|
||||
- Fixed: Original CF shouldn't need to be named "Original"
|
||||
|
||||
- Fixed NullRef in Skyhook Proxy during List Sync
|
||||
|
||||
- Fixed: Remove Notifiarr Environment Option
|
||||
|
||||
- Fixed: Trakt list request now uses correct rules for generating slug (#7449)
|
||||
|
||||
- Fixed: Allow blank ReleaseGroup and Edition from MovieFile edit
|
||||
|
||||
- Fixed: Don't process files that don't have a supported media file extension
|
||||
|
||||
- Fixed: Avoid failure if list contains same movie but without tmdbid
|
||||
|
||||
- Fixed: Log correct path when moving movies (#7439)
|
||||
|
||||
- Fixed: Watch state not preserved on metadata rewrite (#7436)
|
||||
|
||||
- Fixed: NullRefException in TorrentRssParser
|
||||
|
||||
- Bump Version to 4.2.1
|
||||
|
||||
- Fixed: Parse Group ZØNEHD
|
||||
|
||||
- New: Parse Group HONE
|
||||
|
||||
- New: (Discord) Include Custom Formats & Score On Grab
|
||||
|
||||
- Translated using Weblate (Catalan) [skip ci]
|
||||
|
||||
- Fixed: User Triggered Auto Searches now ignores monitored status (#7422)
|
||||
|
||||
- Fixed: Postgres timezone issues (#7183)
|
||||
|
||||
- Speed up and reduce meta calls for Imdb Lists when mapping
|
||||
|
||||
- Fixed: ImportListMovies not saved if from a list without TMDBIds
|
||||
|
||||
- Match 'HQCAM' as CAM source (#7412)
|
||||
|
||||
- Fix RefreshMovieServiceFixture folder service mock
|
||||
|
||||
- Fixed: Collections not deleted on Movie Delete
|
||||
|
||||
- Fixed: Bulk Collection RootFolder change failure
|
||||
|
||||
- New: Collection Folder, Genre, QualityProfile Filters
|
||||
|
||||
- Fixed: Trim RootFolderPath on Migration
|
||||
|
||||
- Avoid multiple metadata DB calls on list mapping
|
||||
|
||||
- Fixed: Prevent excluded movies from being added by collections
|
||||
|
||||
- Fixed: Avoid NullRef in MapMovieToTmdbMovie
|
||||
|
||||
- Fixed: Notifiarr - Better HTTP Error Handling
|
||||
|
||||
- Fix Nullref on Collection delete
|
||||
|
||||
- New: (Notifiarr) Custom Formats in OnGrab
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Custom Format Spec Validation
|
||||
|
||||
- Fixed: Don't fail on single failure for Discover bulk add
|
||||
|
||||
- Remove general yarn restore key to avoid cross OS conflict
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Fixed: Don't call for server notifications on event driven check
|
||||
|
||||
- Rename MovieImportedEvent to MovieFileImportedEvent
|
||||
|
||||
- Fixed: Improved parsing WebDL Releases
|
||||
|
||||
- New: adding a link to tmdb in the import combobox movie search results (#7352)
|
||||
|
||||
- Fixed: Housekeeper doesn't remove collections that have MovieMeta from lists
|
||||
|
||||
- Fixed: Notify on Bulk Adds (Lists, Collections, Imports)
|
||||
|
||||
- Updated NLog Version (#7365)
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Fixed: Migration 208 fails when collection doesn't have name
|
||||
|
||||
- Fixed: Don't call AddMovies if no movies to add from Collection
|
||||
|
||||
- New: Default to IMDb Ratings in Kodi Metadata
|
||||
|
||||
- Translated using Weblate (Slovak) [skip ci]
|
||||
|
||||
- New: Separate Ratings Columns
|
||||
|
||||
- Fixed: Add support for more Anime release formats
|
||||
|
||||
- Translated using Weblate (Portuguese) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Bulk Edit Collections Profile, Root, Availability
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Fixed: Collections Improvements
|
||||
|
||||
- Add back Movie Credits and Alt Titles Indexes
|
||||
|
||||
- Fixed: Validate if equals or child for startup folder
|
||||
|
||||
- New: Notifiarr include Media Info in Download Notifications
|
||||
|
||||
- New: Notifiarr moved from webhook to API
|
||||
|
||||
- Translated using Weblate (German) [skip ci]
|
||||
|
||||
- Use DryIoc for Automoqer, drop Unity dependency
|
||||
|
||||
- Additional logging for partial Plex path scan
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Fixed: Improved empty root folder failsafe logging (#7341)
|
||||
|
||||
- Fixed: Register PostgresOptions when running in utility mode
|
||||
|
||||
- Fixed: Clarified genre filtering helptext on Trakt lists
|
||||
|
||||
- Fixed: Lithuanian media info parsing
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Fixed: MovieAdded trigger not available in UI
|
||||
|
||||
- New: Movie Added Notification
|
||||
|
||||
- Cleanup Collections UI Options
|
||||
|
||||
- Fixed: Speed up Collections API Endpoint
|
||||
|
||||
- New: Add DB Indexes for MovieMetadata
|
||||
|
||||
- New: .NET 6.0.5
|
||||
|
||||
- Translated using Weblate (Polish) [skip ci]
|
||||
|
||||
- Fixed: Remove Collection on last Movie delete
|
||||
|
||||
- Fixed: Correctly use loadash in FE Migrations
|
||||
|
||||
- Fixed: Partial Revert CF Validation for more robust solution
|
||||
|
||||
- Ensure .Mono and .Windows projects have all dependencies in build output
|
||||
|
||||
- Fix frontend monitor migration
|
||||
|
||||
- Try to fix CF null error for imported movie files
|
||||
|
||||
- Tweak monitor migration to avoid overwrites of valid settings
|
||||
|
||||
- Fixed: Run Frontend Migration for MonitorType
|
||||
|
||||
- New: Improve validation errors for Custom Formats
|
||||
|
||||
- Fixed: Don't Import Files with lower CF Score
|
||||
|
||||
- Fixed: Parse UHD2BD as BluRay instead of HDTV
|
||||
|
||||
- Fixed: Bluray 576p parsing
|
||||
|
||||
- New: Release Group Custom Format (#7154)
|
||||
|
||||
- Added term "brazilian" to Brazilian Portuguese parsing (#7296)
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Don't default manual import to move
|
||||
|
||||
- Fixed: Cutoff Unmet showing items above lowest accepted quality when upgrades are disabled
|
||||
|
||||
- New: Collections View
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- New: Parse QxR Group r00t
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Instance name in System/Status API endpoint
|
||||
|
||||
- New: Instance name for Page Title
|
||||
|
||||
- New: Instance Name used for Syslog
|
||||
|
||||
- New: Set Instance Name
|
||||
|
||||
- New: Add optional Source Title column to history
|
||||
|
||||
- New: Support for new Nyaa RSS Feed format
|
||||
|
||||
- Fixed: Don't try to add MovieMeta if mapping fails for list items
|
||||
|
||||
- Fixed: Importing file from UNC shared folder without job folder
|
||||
|
||||
- Fixed: No restart requirement for Refresh Monitored interval change
|
||||
|
||||
- Fixed: Correct User-Agent api logging
|
||||
|
||||
- Delete nan.json
|
||||
|
||||
- Delete zh_Hans.json
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified)) [skip ci]
|
||||
|
||||
- Fixed: Wrong translation mapping can be used for file naming and metadata
|
||||
|
||||
- Fixed: Translated fields are mapped incorrectly for existing search results
|
||||
|
||||
- Fixed: UI hiding search results with duplicate GUIDs
|
||||
|
||||
- Fixed: QBittorrent unknown download state: forcedMetaDL
|
||||
|
||||
- Fix migration 207 distinct on tmdbid only for list movie insert
|
||||
|
||||
- Fix metadata migration
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- Rework Movie Metadata data model
|
||||
|
||||
- Temporarily ignore update tests until linux-x86 released
|
||||
|
||||
- New: Add linux-x86 builds
|
||||
|
||||
- New: Support Plex API Path Scan (Similar to autoscan)
|
||||
|
||||
- Fixed: Interactive Search Filter not filtering multiple qualities in the same filter row
|
||||
|
||||
- Added padding to search tab to maintain visual consistancy
|
||||
|
||||
- Fixed: Update ScheduledTask cache LastStartTime on command execution
|
||||
|
||||
- Bump Version to 4.2
|
||||
|
||||
- Bump webpack packages
|
||||
|
||||
- Remove old DotNetVersion method and dep
|
||||
|
||||
- Bump Monotorrent to 2.0.5
|
||||
|
||||
- Fixed: Don't die if Plex watchlist guid node is missing or null
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Add support for Plex Watchlist importing (#5707)
|
||||
|
||||
- New: Add date picker for custom filter dates
|
||||
|
||||
- Make postgres integration tests actually use postgres
|
||||
|
||||
- Fixed: Clarify Qbit Content Path Error
|
||||
|
||||
- Fixed: Use Movie Original Language for Custom Format Original Language (#6882)
|
||||
|
||||
- Fix .editorconfig to disallow `this`
|
||||
|
||||
- FFMpeg 5.0.1
|
||||
|
||||
- Fixed: Properly handle 119 error code from Synology Download Station
|
||||
|
||||
- Translated using Weblate (Hungarian) [skip ci]
|
||||
|
||||
- Fixed: FFprobe failing on MacOS and AV1 streams
|
||||
|
||||
- add 576 resolution back to simple title regex
|
||||
|
||||
- Translated using Weblate (Ukrainian) [skip ci]
|
||||
|
||||
- Set up tests on postgres
|
||||
|
||||
- Allow configuring postgres with environment variables
|
||||
|
||||
- New: Postgres Support
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,305 +0,0 @@
|
||||
# New Beta Release
|
||||
|
||||
Radarr v4.5.1.7282 has been released on `develop`
|
||||
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
|
||||
# Announcements
|
||||
|
||||
- Radarr Plex Watchlist Improvements
|
||||
- Parsing Improvements
|
||||
|
||||
# Additional Commentary
|
||||
|
||||
|
||||
|
||||
# Releases
|
||||
|
||||
## Native
|
||||
|
||||
- [GitHub Releases](https://github.com/Radarr/Radarr/releases)
|
||||
|
||||
- [Wiki Installation Instructions](https://wiki.servarr.com/radarr/installation)
|
||||
|
||||
## Docker
|
||||
|
||||
- [hotio/Radarr:testing](https://hotio.dev/containers/radarr)
|
||||
|
||||
- [lscr.io/linuxserver/Radarr:develop](https://docs.linuxserver.io/images/docker-radarr)
|
||||
|
||||
## NAS Packages
|
||||
|
||||
- Synology - Please ask the SynoCommunity to update the base package; however, you can update in-app normally
|
||||
|
||||
- QNAP - Please ask the QNAP to update the base package; however, you should be able to update in-app normally
|
||||
|
||||
------------
|
||||
|
||||
# Release Notes
|
||||
|
||||
## v4.5.1.7282 (changes since v4.5.0.7106)
|
||||
|
||||
- Add back min availability to bulk movie edit
|
||||
|
||||
- Clean up variable name case
|
||||
|
||||
- Fix Radarr import syncing not matching any root folders.
|
||||
|
||||
- Fix MovieFileLanguageConnector to use MovieLanguage
|
||||
|
||||
- Update UI dependencies
|
||||
|
||||
- Add `inset` to stylelintrc
|
||||
|
||||
- Remove unused babel plugins and fix build with profiling
|
||||
|
||||
- Update all relevant dev tool deps
|
||||
|
||||
- Delete various old config files
|
||||
|
||||
- Use `await using` in LocalizationService
|
||||
|
||||
- Fixed: Provider health checks persist after add until next scheduled check
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- New: Log additional information when processing completed torrents from rTorrent
|
||||
|
||||
- Fix function name and use out var for try get in DownloadClientProvider
|
||||
|
||||
- Add Pull Request Labeler
|
||||
|
||||
- API key improvements
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Notifications when Manual Interaction is required for importing
|
||||
|
||||
- New: On Health Restored notification
|
||||
|
||||
- Why rename many files when few file do trick
|
||||
|
||||
- GracePeriod not Graceperiod
|
||||
|
||||
- Sort translations alphabetically
|
||||
|
||||
- Move vscode settings to the frontend folder
|
||||
|
||||
- Fixed IsValidPath usages
|
||||
|
||||
- New: Improve path validation when handling paths from different OSes
|
||||
|
||||
- Log invalid config file exceptions
|
||||
|
||||
- Add VSCode extension recommendations
|
||||
|
||||
- Fixed: Ensure indexer errors are handled before processing response
|
||||
|
||||
- Align environment variable setting in ProcessProvider with upstream
|
||||
|
||||
- New: Only add version header for API requests
|
||||
|
||||
- Fixed: RootFolderPath not set for Movies from API
|
||||
|
||||
- Fixed: Index UI crash for movies without files
|
||||
|
||||
- New: Add token authentication for ntfy.sh notifications
|
||||
|
||||
- Fixed: Matching of custom formats during movie file import
|
||||
|
||||
- Revert argument exception swallowing for Plex library update
|
||||
|
||||
- New: Improved Plex library updating
|
||||
|
||||
- New: Add release info to webhook/custom script import events
|
||||
|
||||
- New: Don't import movies that don't match grab history
|
||||
|
||||
- Use string interpolation for Newznab request generation
|
||||
|
||||
- Virtualize movie select for manual import with react-window
|
||||
|
||||
- Convert Manual Import to Typescript
|
||||
|
||||
- New: Log content for invalid torrent files
|
||||
|
||||
- Translated using Weblate (Portuguese (Brazil)) [skip ci]
|
||||
|
||||
- Add `tmdbid` to capabilities check in Newznab/Torznab
|
||||
|
||||
- Remove requirement for imdbtitle and imdbyear in Newznab and Torznab
|
||||
|
||||
- Remove duplicate check in RemotePathMappingCheck
|
||||
|
||||
- Fixed: Movie Status in Table View
|
||||
|
||||
- Automated API Docs update
|
||||
|
||||
- New: Add result to commands to report commands that did not complete successfully
|
||||
|
||||
- Translated using Weblate (French) [skip ci]
|
||||
|
||||
- add trace log checkbox to bug report [common]
|
||||
|
||||
- Migrate to FluentValidation 9
|
||||
|
||||
- Fix downloading releases without an indexer
|
||||
|
||||
- Build download requests from indexer implementation
|
||||
|
||||
- bump `lock threads` github action to latest [skip ci]
|
||||
|
||||
- Fixed some aria violations
|
||||
|
||||
- Fixed: Search Button Display on Movie Index
|
||||
|
||||
- Fixed: Unable to search individual movies from Movie Index
|
||||
|
||||
- Fixed: Upgrades blocked: UpgradeSpecification error
|
||||
|
||||
- Fixed: Cannot Toggle Show Search on Movie Index
|
||||
|
||||
- New: Filter Sonarr synchronization based on Root Folders
|
||||
|
||||
- New: Add Original Language as Filter Option in Discover View
|
||||
|
||||
- New: Handle multi title release names split by slash
|
||||
|
||||
- Translated using Weblate (Chinese (Simplified) (zh_CN)) [skip ci]
|
||||
|
||||
- Fixed: Don't import Custom Format downgrades
|
||||
|
||||
- Fixed: Enable parsing of repacks with revision
|
||||
|
||||
- Fixed: Don't clean Kodi library if video is playing and Always Update is disabled
|
||||
|
||||
- Revert "Build download requests from indexer implementation"
|
||||
|
||||
- Fixed: Movie count incorrect in Movie Editor
|
||||
|
||||
- Fixed: Missing Translates
|
||||
|
||||
- Simplify DatabaseType logic
|
||||
|
||||
- Fixed: (Database) Improve Version detection
|
||||
|
||||
- Fixed: Importing from Manual Import ignoring Analyze video files
|
||||
|
||||
- Extract useSelectState from SelectContext
|
||||
|
||||
- Avoid queue failures due to unknown release language processing
|
||||
|
||||
- Fix default value variable name for ImportListExclusion
|
||||
|
||||
- New: Closing Move Movie modal without selecting will cancel save
|
||||
|
||||
- Use augmented languages for queue items
|
||||
|
||||
- New: Use languages from Torznab/Newznab attributes if given
|
||||
|
||||
- New: Use TmdbId from parsing for mapping
|
||||
|
||||
- Cleanup ParsingService
|
||||
|
||||
- Fixed: Pushed releases should be stored as pushed release
|
||||
|
||||
- New: Don't block imports when release was matched by ID if they were grabbed via interactive search
|
||||
|
||||
- Fixed: Queue not showing items with conflicting titles
|
||||
|
||||
- New: Include Movie Match Type in grab event details
|
||||
|
||||
- Fixed: Automatic import of releases when file is not matched to movie
|
||||
|
||||
- Fixed: Don't automatically import if release title doesn't match movie title
|
||||
|
||||
- Fixed: Throw to manual import if multiple movies found during title mapping
|
||||
|
||||
- Build download requests from indexer implementation
|
||||
|
||||
- New: Updated button and calendar outline colors for dark theme
|
||||
|
||||
- Fix loading eslintrc
|
||||
|
||||
- New: Remember add import list exclusion when removing movie
|
||||
|
||||
- Fixed: Movies table not resizing properly when window size changed
|
||||
|
||||
- Fixed: Movie select not working correctly after stopping/starting or changing sort order
|
||||
|
||||
- Improved UI error messages (stack trace and version)
|
||||
|
||||
- New: Increase clickable area of movie select in poster/overview
|
||||
|
||||
- Remove unused ReactDOM import
|
||||
|
||||
- Fixed: File browser
|
||||
|
||||
- Remove movie editor code
|
||||
|
||||
- New: Mass Editor is now part of movie list
|
||||
|
||||
- Added movie index selection
|
||||
|
||||
- Fixed: Restoring scroll position when going back/forward to series list
|
||||
|
||||
- Refactor Movie index to use react-window
|
||||
|
||||
- Add CSS Typings
|
||||
|
||||
- Add Prettier to format TypeScript files
|
||||
|
||||
- Add typescript
|
||||
|
||||
- New: Parsing of more German WEBDL releases
|
||||
|
||||
- Fixed: Parse 720p Remux as 720p BluRay
|
||||
|
||||
- QualityParser - Simplify new expression (IDE0090)
|
||||
|
||||
- Misc HealthCheck Cleanup and Sonarr Alignment
|
||||
|
||||
- Bump Swashbuckle to 6.5.0
|
||||
|
||||
- Fixed: Ensure first history item when marked as failed is the selected item
|
||||
|
||||
- Fixed: Edit Quality Profile not opening
|
||||
|
||||
- Refactor LanguageParser.ParseLanguageTags() to return List<> instead of IEnumerable. Clean up calls to ParseLanguageTags().
|
||||
|
||||
- Include extra tags from existing subtitles when renaming.
|
||||
|
||||
- Translated using Weblate (French) [skip ci]
|
||||
|
||||
- Use BuildInfo.AppName for RARBG appId instead of hardcoded value
|
||||
|
||||
- New: Updated Rarbg request limits
|
||||
|
||||
- New: Report health error if Recycling Bin folder is not writable
|
||||
|
||||
- Update core-js and use defaults for browserlist
|
||||
|
||||
- Update webpack and webpack-cli
|
||||
|
||||
- Use minified jquery
|
||||
|
||||
- Remove unused gulpFile
|
||||
|
||||
- Fix typo in calendarBackgroundColor CSS variable
|
||||
|
||||
- Fix QualityParser Tests
|
||||
|
||||
- Fixed: Parse DVD with 576p Resolution as DVD
|
||||
|
||||
- Auto-reply for Log Label [common]
|
||||
|
||||
- Bump version to 4.5.1
|
||||
|
||||
- Other bug fixes and improvements, see GitHub history
|
||||
@@ -1,2 +0,0 @@
|
||||
- Radarr Plex Watchlist Improvements
|
||||
- Parsing Improvements
|
||||
@@ -1,6 +0,0 @@
|
||||
- **Users who do not wish to be on the alpha `nightly` testing branch should take advantage of this parity and switch to `develop`**
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
@@ -1,6 +0,0 @@
|
||||
- **Users who do not wish to be on the alpha `nightly` or beta `develop` testing branches should take advantage of this parity and switch to `master`
|
||||
|
||||
A reminder about the `develop` and `nightly` branches
|
||||
|
||||
- **develop - Current Develop/Beta - (Beta): This is the testing edge. Released after tested in nightly to ensure no immediate issues. New features and bug fixes released here first after nightly. It can be considered semi-stable, but is still beta. This version will receive updates either weekly or biweekly depending on development.**
|
||||
- **nightly - Current Nightly/Unstable - (Alpha/Unstable) : This is the bleeding edge. It is released as soon as code is committed and passes all automated tests. This build may have not been used by us or other users yet. There is no guarantee that it will even run in some cases. This branch is only recommended for advanced users. Issues and self investigation are expected in this branch. Use this branch only if you know what you are doing and are willing to get your hands dirty to recover a failed update. This version is updated immediately.**
|
||||
5
debian/changelog
vendored
5
debian/changelog
vendored
@@ -1,5 +0,0 @@
|
||||
nzbdrone {version} {branch}; urgency=low
|
||||
|
||||
* Automatic Release.
|
||||
|
||||
-- NzbDrone <contact@nzbdrone.com> Mon, 26 Aug 2013 00:00:00 -0700
|
||||
1
debian/compat
vendored
1
debian/compat
vendored
@@ -1 +0,0 @@
|
||||
8
|
||||
12
debian/control
vendored
12
debian/control
vendored
@@ -1,12 +0,0 @@
|
||||
Section: web
|
||||
Priority: optional
|
||||
Maintainer: Sonarr <contact@nzbdrone.com>
|
||||
Source: nzbdrone
|
||||
Homepage: https://sonarr.tv
|
||||
Vcs-Git: git@github.com:Sonarr/Sonarr.git
|
||||
Vcs-Browser: https://github.com/Sonarr/Sonarr
|
||||
|
||||
Package: nzbdrone
|
||||
Architecture: all
|
||||
Depends: libmono-cil-dev (>= 3.2), sqlite3 (>= 3.7), mediainfo (>= 0.7.52)
|
||||
Description: Sonarr is an internet PVR
|
||||
24
debian/copyright
vendored
24
debian/copyright
vendored
@@ -1,24 +0,0 @@
|
||||
Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
|
||||
Upstream-Name: nzbdrone
|
||||
Source: https://github.com/Sonarr/Sonarr
|
||||
|
||||
Files: *
|
||||
Copyright: 2010-2016 Sonarr <hello@sonarr.tv>
|
||||
|
||||
License: GPL-3.0+
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
.
|
||||
This package is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
.
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
.
|
||||
On Debian systems, the complete text of the GNU General
|
||||
Public License version 3 can be found in "/usr/share/common-licenses/GPL-3".
|
||||
1
debian/install
vendored
1
debian/install
vendored
@@ -1 +0,0 @@
|
||||
nzbdrone_bin/* opt/NzbDrone
|
||||
13
debian/rules
vendored
13
debian/rules
vendored
@@ -1,13 +0,0 @@
|
||||
#!/usr/bin/make -f
|
||||
# -*- makefile -*-
|
||||
# Sample debian/rules that uses debhelper.
|
||||
# This file was originally written by Joey Hess and Craig Small.
|
||||
# As a special exception, when this file is copied by dh-make into a
|
||||
# dh-make output file, you may use that output file without restriction.
|
||||
# This special exception was added by Craig Small in version 0.37 of dh-make.
|
||||
|
||||
# Uncomment this to turn on verbose mode.
|
||||
#export DH_VERBOSE=1
|
||||
|
||||
%:
|
||||
dh $@
|
||||
@@ -52,8 +52,8 @@ Name: "none"; Description: "Do not start automatically"; GroupDescription: "Star
|
||||
Name: "{app}"; Permissions: users-modify
|
||||
|
||||
[Files]
|
||||
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\Radarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
|
||||
Source: "..\_artifacts\{#Runtime}\{#Framework}\Radarr\*"; Excludes: "Radarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Radarr\Radarr.exe"; DestDir: "{app}\bin"; Flags: ignoreversion
|
||||
Source: "..\..\..\_artifacts\{#Runtime}\{#Framework}\Radarr\*"; Excludes: "Radarr.Update"; DestDir: "{app}\bin"; Flags: ignoreversion recursesubdirs createallsubdirs
|
||||
; NOTE: Don't use "Flags: ignoreversion" on any shared system files
|
||||
|
||||
[Icons]
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
@@ -156,16 +157,16 @@ class Blocklist extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadBlocklist')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
isPopulated && !error && !items.length &&
|
||||
<div>
|
||||
{translate('NoHistory')}
|
||||
</div>
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('NoHistoryBlocklist')}
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
@@ -209,7 +210,7 @@ class Blocklist extends Component {
|
||||
isOpen={isConfirmRemoveModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('RemoveSelected')}
|
||||
message={translate('AreYouSureYouWantToRemoveTheSelectedItemsFromBlocklist')}
|
||||
message={translate('RemoveSelectedItemBlocklistMessageText')}
|
||||
confirmLabel={translate('RemoveSelected')}
|
||||
onConfirm={this.onRemoveSelectedConfirmed}
|
||||
onCancel={this.onConfirmRemoveModalClose}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import FilterMenu from 'Components/Menu/FilterMenu';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
@@ -11,7 +12,7 @@ import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import TablePager from 'Components/Table/TablePager';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import HistoryRowConnector from './HistoryRowConnector';
|
||||
|
||||
@@ -83,9 +84,9 @@ class History extends Component {
|
||||
|
||||
{
|
||||
!isFetchingAny && hasError &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadHistory')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
@@ -93,9 +94,9 @@ class History extends Component {
|
||||
// wait for the episodes to populate because they are never coming.
|
||||
|
||||
isPopulated && !hasError && !items.length &&
|
||||
<div>
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('NoHistory')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
@@ -12,7 +13,7 @@ import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import TablePager from 'Components/Table/TablePager';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import getRemovedItems from 'Utilities/Object/getRemovedItems';
|
||||
import hasDifferentItems from 'Utilities/Object/hasDifferentItems';
|
||||
import translate from 'Utilities/String/translate';
|
||||
@@ -231,17 +232,17 @@ class Queue extends Component {
|
||||
|
||||
{
|
||||
!isRefreshing && hasError ?
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('FailedToLoadQueue')}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
{
|
||||
isAllPopulated && !hasError && !items.length ?
|
||||
<div>
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('QueueIsEmpty')}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
@@ -88,7 +88,7 @@ class RemoveQueueItemsModal extends Component {
|
||||
|
||||
<ModalBody>
|
||||
<div className={styles.message}>
|
||||
{selectedCount > 1 ? translate('AreYouSureYouWantToRemoveSelectedItemsFromQueue', selectedCount) : translate('AreYouSureYouWantToRemoveSelectedItemFromQueue')}
|
||||
{selectedCount > 1 ? translate('RemoveSelectedItemsQueueMessageText', selectedCount) : translate('RemoveSelectedItemQueueMessageText')}
|
||||
</div>
|
||||
|
||||
{
|
||||
@@ -133,7 +133,7 @@ class RemoveQueueItemsModal extends Component {
|
||||
kind={kinds.DANGER}
|
||||
onPress={this.onRemoveConfirmed}
|
||||
>
|
||||
Remove
|
||||
{translate('Remove')}
|
||||
</Button>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
import { reduce } from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import selectAll from 'Utilities/Table/selectAll';
|
||||
import toggleSelected from 'Utilities/Table/toggleSelected';
|
||||
@@ -105,9 +107,9 @@ class ImportMovie extends Component {
|
||||
|
||||
{
|
||||
!rootFoldersFetching && !!rootFoldersError ?
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadRootFolders')}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
@@ -116,9 +118,9 @@ class ImportMovie extends Component {
|
||||
!rootFoldersFetching &&
|
||||
rootFoldersPopulated &&
|
||||
!unmappedFolders.length ?
|
||||
<div>
|
||||
<Alert kind={kinds.INFO}>
|
||||
{translate('AllMoviesInPathHaveBeenImported', [path])}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
@@ -92,9 +92,9 @@ class ImportMovieSelectFolder extends Component {
|
||||
|
||||
{
|
||||
!isFetching && error ?
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadRootFolders')}
|
||||
</div> :
|
||||
</Alert> :
|
||||
null
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,33 @@
|
||||
import AppSectionState, {
|
||||
AppSectionDeleteState,
|
||||
AppSectionSaveState,
|
||||
AppSectionSchemaState,
|
||||
} from 'App/State/AppSectionState';
|
||||
import Language from 'Language/Language';
|
||||
import DownloadClient from 'typings/DownloadClient';
|
||||
import ImportList from 'typings/ImportList';
|
||||
import Indexer from 'typings/Indexer';
|
||||
import Notification from 'typings/Notification';
|
||||
import QualityProfile from 'typings/QualityProfile';
|
||||
import { UiSettings } from 'typings/UiSettings';
|
||||
|
||||
export interface DownloadClientAppState
|
||||
extends AppSectionState<DownloadClient>,
|
||||
AppSectionDeleteState,
|
||||
AppSectionSaveState {}
|
||||
|
||||
export interface ImportListAppState
|
||||
extends AppSectionState<ImportList>,
|
||||
AppSectionDeleteState,
|
||||
AppSectionSaveState {}
|
||||
|
||||
export interface IndexerAppState
|
||||
extends AppSectionState<Indexer>,
|
||||
AppSectionDeleteState,
|
||||
AppSectionSaveState {}
|
||||
|
||||
export interface NotificationAppState
|
||||
extends AppSectionState<Notification>,
|
||||
AppSectionDeleteState {}
|
||||
|
||||
export interface QualityProfilesAppState
|
||||
@@ -20,6 +39,9 @@ export type UiSettingsAppState = AppSectionState<UiSettings>;
|
||||
|
||||
interface SettingsAppState {
|
||||
downloadClients: DownloadClientAppState;
|
||||
importLists: ImportListAppState;
|
||||
indexers: IndexerAppState;
|
||||
notifications: NotificationAppState;
|
||||
language: LanguageSettingsAppState;
|
||||
uiSettings: UiSettingsAppState;
|
||||
qualityProfiles: QualityProfilesAppState;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import AgendaConnector from './Agenda/AgendaConnector';
|
||||
import * as calendarViews from './calendarViews';
|
||||
@@ -31,9 +33,9 @@ class Calendar extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadTheCalendar')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
@@ -9,7 +10,7 @@ import PageToolbar from 'Components/Page/Toolbar/PageToolbar';
|
||||
import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
|
||||
import styles from 'Movie/Index/MovieIndex.css';
|
||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||
import translate from 'Utilities/String/translate';
|
||||
@@ -313,9 +314,9 @@ class Collection extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadCollections')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -265,6 +265,8 @@ FormInputGroup.propTypes = {
|
||||
values: PropTypes.arrayOf(PropTypes.any),
|
||||
type: PropTypes.string.isRequired,
|
||||
kind: PropTypes.oneOf(kinds.all),
|
||||
min: PropTypes.number,
|
||||
max: PropTypes.number,
|
||||
unit: PropTypes.string,
|
||||
buttons: PropTypes.oneOfType([PropTypes.node, PropTypes.arrayOf(PropTypes.node)]),
|
||||
helpText: PropTypes.string,
|
||||
|
||||
@@ -10,7 +10,7 @@ function parseValue(props, value) {
|
||||
} = props;
|
||||
|
||||
if (value == null || value === '') {
|
||||
return min;
|
||||
return null;
|
||||
}
|
||||
|
||||
let newValue = isFloat ? parseFloat(value) : parseInt(value);
|
||||
|
||||
@@ -63,6 +63,7 @@ function ProviderFieldFormGroup(props) {
|
||||
name,
|
||||
label,
|
||||
helpText,
|
||||
helpTextWarning,
|
||||
helpLink,
|
||||
placeholder,
|
||||
value,
|
||||
@@ -96,6 +97,7 @@ function ProviderFieldFormGroup(props) {
|
||||
name={name}
|
||||
label={label}
|
||||
helpText={helpText}
|
||||
helpTextWarning={helpTextWarning}
|
||||
helpLink={helpLink}
|
||||
placeholder={placeholder}
|
||||
value={value}
|
||||
@@ -122,6 +124,7 @@ ProviderFieldFormGroup.propTypes = {
|
||||
name: PropTypes.string.isRequired,
|
||||
label: PropTypes.string.isRequired,
|
||||
helpText: PropTypes.string,
|
||||
helpTextWarning: PropTypes.string,
|
||||
helpLink: PropTypes.string,
|
||||
placeholder: PropTypes.string,
|
||||
value: PropTypes.any,
|
||||
|
||||
@@ -13,7 +13,7 @@ const messages = [
|
||||
'Loading humorous message... Please Wait',
|
||||
'I could\'ve been faster in Python',
|
||||
'Don\'t forget to rewind your movies',
|
||||
'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!',
|
||||
'RE-calibrating the internet...',
|
||||
'I\'ll be here all week',
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
|
||||
function PageSectionContent(props) {
|
||||
const {
|
||||
@@ -17,7 +19,7 @@ function PageSectionContent(props) {
|
||||
);
|
||||
} else if (!isFetching && !!error) {
|
||||
return (
|
||||
<div>{errorMessage}</div>
|
||||
<Alert kind={kinds.DANGER}>{errorMessage}</Alert>
|
||||
);
|
||||
} else if (isPopulated && !error) {
|
||||
return (
|
||||
|
||||
@@ -16,6 +16,46 @@
|
||||
box-shadow: inset 0 -1px 0 rgba(0, 0, 0, 0.15);
|
||||
color: var(--white);
|
||||
transition: width 0.6s ease;
|
||||
|
||||
&.default {
|
||||
background-color: var(--darkGray);
|
||||
}
|
||||
|
||||
&.primary {
|
||||
background-color: var(--primaryColor);
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background-color: var(--dangerColor);
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
|
||||
}
|
||||
}
|
||||
|
||||
&.success {
|
||||
background-color: var(--successColor);
|
||||
}
|
||||
|
||||
&.purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background-color: var(--warningColor);
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
|
||||
}
|
||||
}
|
||||
|
||||
&.info {
|
||||
background-color: var(--infoColor);
|
||||
}
|
||||
|
||||
&.queue {
|
||||
background-color: var(--queueColor);
|
||||
}
|
||||
}
|
||||
|
||||
.frontTextContainer {
|
||||
@@ -45,42 +85,6 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.primary {
|
||||
background-color: var(--primaryColor);
|
||||
}
|
||||
|
||||
.danger {
|
||||
background-color: var(--dangerColor);
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(90deg, color(#f05050 shade(5%)), color(#f05050 shade(5%)) 5px, color(#f05050 shade(15%)) 5px, color(#f05050 shade(15%)) 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.success {
|
||||
background-color: var(--successColor);
|
||||
}
|
||||
|
||||
.purple {
|
||||
background-color: var(--purple);
|
||||
}
|
||||
|
||||
.warning {
|
||||
background-color: var(--warningColor);
|
||||
|
||||
&:global(.colorImpaired) {
|
||||
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
|
||||
}
|
||||
}
|
||||
|
||||
.info {
|
||||
background-color: var(--infoColor);
|
||||
}
|
||||
|
||||
.queue {
|
||||
background-color: var(--queueColor);
|
||||
}
|
||||
|
||||
.small {
|
||||
height: $progressBarSmallHeight;
|
||||
|
||||
|
||||
1
frontend/src/Components/ProgressBar.css.d.ts
vendored
1
frontend/src/Components/ProgressBar.css.d.ts
vendored
@@ -5,6 +5,7 @@ interface CssExports {
|
||||
'backTextContainer': string;
|
||||
'container': string;
|
||||
'danger': string;
|
||||
'default': string;
|
||||
'frontText': string;
|
||||
'frontTextContainer': string;
|
||||
'info': string;
|
||||
|
||||
@@ -38,7 +38,7 @@ function ProgressBar(props) {
|
||||
{
|
||||
showText && width ?
|
||||
<div
|
||||
className={styles.backTextContainer}
|
||||
className={classNames(styles.backTextContainer, styles[kind])}
|
||||
style={{ width: actualWidth }}
|
||||
>
|
||||
<div className={styles.backText}>
|
||||
@@ -67,7 +67,7 @@ function ProgressBar(props) {
|
||||
{
|
||||
showText ?
|
||||
<div
|
||||
className={styles.frontTextContainer}
|
||||
className={classNames(styles.frontTextContainer, styles[kind])}
|
||||
style={{ width: progressPercent }}
|
||||
>
|
||||
<div
|
||||
|
||||
4
frontend/src/Components/Table/VirtualTableRowButton.css
Normal file
4
frontend/src/Components/Table/VirtualTableRowButton.css
Normal file
@@ -0,0 +1,4 @@
|
||||
.row {
|
||||
composes: link from '~Components/Link/Link.css';
|
||||
composes: row from '~./VirtualTableRow.css';
|
||||
}
|
||||
7
frontend/src/Components/Table/VirtualTableRowButton.css.d.ts
vendored
Normal file
7
frontend/src/Components/Table/VirtualTableRowButton.css.d.ts
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'row': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
16
frontend/src/Components/Table/VirtualTableRowButton.js
Normal file
16
frontend/src/Components/Table/VirtualTableRowButton.js
Normal file
@@ -0,0 +1,16 @@
|
||||
import React from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import VirtualTableRow from './VirtualTableRow';
|
||||
import styles from './VirtualTableRowButton.css';
|
||||
|
||||
function VirtualTableRowButton(props) {
|
||||
return (
|
||||
<Link
|
||||
className={styles.row}
|
||||
component={VirtualTableRow}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
export default VirtualTableRowButton;
|
||||
@@ -1,4 +1,3 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
@@ -6,16 +5,15 @@ import Label from './Label';
|
||||
import styles from './TagList.css';
|
||||
|
||||
function TagList({ tags, tagList }) {
|
||||
const sortedTags = tags
|
||||
.map((tagId) => tagList.find((tag) => tag.id === tagId))
|
||||
.filter((tag) => !!tag)
|
||||
.sort((a, b) => a.label.localeCompare(b.label));
|
||||
|
||||
return (
|
||||
<div className={styles.tags}>
|
||||
{
|
||||
tags.map((t) => {
|
||||
const tag = _.find(tagList, { id: t });
|
||||
|
||||
if (!tag) {
|
||||
return null;
|
||||
}
|
||||
|
||||
sortedTags.map((tag) => {
|
||||
return (
|
||||
<Label
|
||||
key={tag.id}
|
||||
|
||||
@@ -2,16 +2,17 @@
|
||||
"name": "Radarr",
|
||||
"icons": [
|
||||
{
|
||||
"src": "/Content/Images/Icons/android-chrome-192x192.png",
|
||||
"src": "android-chrome-192x192.png",
|
||||
"sizes": "192x192",
|
||||
"type": "image/png"
|
||||
},
|
||||
{
|
||||
"src": "/Content/Images/Icons/android-chrome-512x512.png",
|
||||
"src": "android-chrome-512x512.png",
|
||||
"sizes": "512x512",
|
||||
"type": "image/png"
|
||||
}
|
||||
],
|
||||
"start_url": "../../../../",
|
||||
"theme_color": "#3a3f51",
|
||||
"background_color": "#3a3f51",
|
||||
"display": "standalone"
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
@@ -10,7 +11,7 @@ import PageToolbarButton from 'Components/Page/Toolbar/PageToolbarButton';
|
||||
import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import { align, icons, sortDirections } from 'Helpers/Props';
|
||||
import { align, icons, kinds, sortDirections } from 'Helpers/Props';
|
||||
import styles from 'Movie/Index/MovieIndex.css';
|
||||
import hasDifferentItemsOrOrder from 'Utilities/Object/hasDifferentItemsOrOrder';
|
||||
import translate from 'Utilities/String/translate';
|
||||
@@ -369,9 +370,9 @@ class DiscoverMovie extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadMovies')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -71,6 +71,7 @@ import {
|
||||
faLanguage as fasLanguage,
|
||||
faLaptop as fasLaptop,
|
||||
faLevelUpAlt as fasLevelUpAlt,
|
||||
faListCheck as fasListCheck,
|
||||
faMedkit as fasMedkit,
|
||||
faMinus as fasMinus,
|
||||
faPause as fasPause,
|
||||
@@ -172,6 +173,7 @@ export const INFO = fasInfoCircle;
|
||||
export const INTERACTIVE = fasUser;
|
||||
export const KEYBOARD = farKeyboard;
|
||||
export const LOGOUT = fasSignOutAlt;
|
||||
export const MANAGE = fasListCheck;
|
||||
export const MEDIA_INFO = farFileInvoice;
|
||||
export const MISSING = fasExclamationTriangle;
|
||||
export const MONITORED = fasBookmark;
|
||||
|
||||
@@ -2,6 +2,7 @@ import React, { useCallback, useState } from 'react';
|
||||
import { useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { LanguageSettingsAppState } from 'App/State/SettingsAppState';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -86,7 +87,9 @@ function SelectLanguageModalContent(props: SelectLanguageModalContentProps) {
|
||||
{isFetching ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isFetching && error ? (
|
||||
<div>{translate('UnableToLoadLanguages')}</div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadLanguages')}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{isPopulated && !error ? (
|
||||
|
||||
@@ -15,13 +15,40 @@ import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Scroller from 'Components/Scroller/Scroller';
|
||||
import Column from 'Components/Table/Column';
|
||||
import VirtualTableRowButton from 'Components/Table/VirtualTableRowButton';
|
||||
import { scrollDirections } from 'Helpers/Props';
|
||||
import Movie from 'Movie/Movie';
|
||||
import createAllMoviesSelector from 'Store/Selectors/createAllMoviesSelector';
|
||||
import dimensions from 'Styles/Variables/dimensions';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import SelectMovieModalTableHeader from './SelectMovieModalTableHeader';
|
||||
import SelectMovieRow from './SelectMovieRow';
|
||||
import styles from './SelectMovieModalContent.css';
|
||||
|
||||
const columns = [
|
||||
{
|
||||
name: 'title',
|
||||
label: translate('Title'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'year',
|
||||
label: translate('Year'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'imdbId',
|
||||
label: translate('ImdbId'),
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'tmdbId',
|
||||
label: translate('TmdbId'),
|
||||
isVisible: true,
|
||||
},
|
||||
];
|
||||
|
||||
const bodyPadding = parseInt(dimensions.pageContentBodyPadding);
|
||||
|
||||
interface SelectMovieModalContentProps {
|
||||
@@ -32,6 +59,7 @@ interface SelectMovieModalContentProps {
|
||||
|
||||
interface RowItemData {
|
||||
items: Movie[];
|
||||
columns: Column[];
|
||||
onMovieSelect(movieId: number): void;
|
||||
}
|
||||
|
||||
@@ -40,7 +68,7 @@ const Row: React.FC<ListChildComponentProps<RowItemData>> = ({
|
||||
style,
|
||||
data,
|
||||
}) => {
|
||||
const { items, onMovieSelect } = data;
|
||||
const { items, columns, onMovieSelect } = data;
|
||||
|
||||
if (index >= items.length) {
|
||||
return null;
|
||||
@@ -49,20 +77,24 @@ const Row: React.FC<ListChildComponentProps<RowItemData>> = ({
|
||||
const movie = items[index];
|
||||
|
||||
return (
|
||||
<div
|
||||
<VirtualTableRowButton
|
||||
style={{
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
...style,
|
||||
}}
|
||||
onPress={() => onMovieSelect(movie.id)}
|
||||
>
|
||||
<SelectMovieRow
|
||||
id={movie.id}
|
||||
title={movie.title}
|
||||
tmdbId={movie.tmdbId}
|
||||
imdbId={movie.imdbId}
|
||||
year={movie.year}
|
||||
columns={columns}
|
||||
onMovieSelect={onMovieSelect}
|
||||
/>
|
||||
</div>
|
||||
</VirtualTableRowButton>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -161,6 +193,7 @@ function SelectMovieModalContent(props: SelectMovieModalContentProps) {
|
||||
autoFocus={false}
|
||||
ref={scrollerRef}
|
||||
>
|
||||
<SelectMovieModalTableHeader columns={columns} />
|
||||
<List<RowItemData>
|
||||
ref={listRef}
|
||||
style={{
|
||||
@@ -174,6 +207,7 @@ function SelectMovieModalContent(props: SelectMovieModalContentProps) {
|
||||
itemSize={38}
|
||||
itemData={{
|
||||
items,
|
||||
columns,
|
||||
onMovieSelect: onMovieSelectWrapper,
|
||||
}}
|
||||
>
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
.title {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 4 0 140px;
|
||||
}
|
||||
|
||||
.year {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 70px;
|
||||
}
|
||||
|
||||
.imdbId,
|
||||
.tmdbId {
|
||||
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
10
frontend/src/InteractiveImport/Movie/SelectMovieModalTableHeader.css.d.ts
vendored
Normal file
10
frontend/src/InteractiveImport/Movie/SelectMovieModalTableHeader.css.d.ts
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'imdbId': string;
|
||||
'title': string;
|
||||
'tmdbId': string;
|
||||
'year': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,41 @@
|
||||
import React from 'react';
|
||||
import Column from 'Components/Table/Column';
|
||||
import VirtualTableHeader from 'Components/Table/VirtualTableHeader';
|
||||
import VirtualTableHeaderCell from 'Components/Table/VirtualTableHeaderCell';
|
||||
import styles from './SelectMovieModalTableHeader.css';
|
||||
|
||||
interface SelectMovieModalTableHeaderProps {
|
||||
columns: Column[];
|
||||
}
|
||||
|
||||
function SelectMovieModalTableHeader(props: SelectMovieModalTableHeaderProps) {
|
||||
const { columns } = props;
|
||||
|
||||
return (
|
||||
<VirtualTableHeader>
|
||||
{columns.map((column) => {
|
||||
const { name, label, isVisible } = column;
|
||||
|
||||
if (!isVisible) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<VirtualTableHeaderCell
|
||||
key={name}
|
||||
className={
|
||||
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||
// @ts-ignore
|
||||
styles[name]
|
||||
}
|
||||
name={name}
|
||||
>
|
||||
{label}
|
||||
</VirtualTableHeaderCell>
|
||||
);
|
||||
})}
|
||||
</VirtualTableHeader>
|
||||
);
|
||||
}
|
||||
|
||||
export default SelectMovieModalTableHeader;
|
||||
@@ -1,5 +1,25 @@
|
||||
.movie {
|
||||
padding: 8px;
|
||||
width: 100%;
|
||||
border-bottom: 1px solid var(--borderColor);
|
||||
.cell {
|
||||
composes: cell from '~Components/Table/Cells/VirtualTableRowCell.css';
|
||||
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.title {
|
||||
composes: cell;
|
||||
|
||||
flex: 4 0 140px;
|
||||
}
|
||||
|
||||
.year {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 70px;
|
||||
}
|
||||
|
||||
.tmdbId,
|
||||
.imdbId {
|
||||
composes: cell;
|
||||
|
||||
flex: 0 0 110px;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'movie': string;
|
||||
'cell': string;
|
||||
'imdbId': string;
|
||||
'title': string;
|
||||
'tmdbId': string;
|
||||
'year': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Link from 'Components/Link/Link';
|
||||
import Label from 'Components/Label';
|
||||
import VirtualTableRowCell from 'Components/Table/Cells/VirtualTableRowCell';
|
||||
import styles from './SelectMovieRow.css';
|
||||
|
||||
class SelectMovieRow extends Component {
|
||||
@@ -17,13 +18,23 @@ class SelectMovieRow extends Component {
|
||||
|
||||
render() {
|
||||
return (
|
||||
<Link
|
||||
className={styles.movie}
|
||||
component="div"
|
||||
onPress={this.onPress}
|
||||
>
|
||||
{this.props.title} ({this.props.year})
|
||||
</Link>
|
||||
<>
|
||||
<VirtualTableRowCell className={styles.title}>
|
||||
{this.props.title}
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell className={styles.year}>
|
||||
{this.props.year}
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell className={styles.imdbId}>
|
||||
<Label>{this.props.imdbId}</Label>
|
||||
</VirtualTableRowCell>
|
||||
|
||||
<VirtualTableRowCell className={styles.tmdbId}>
|
||||
<Label>{this.props.tmdbId}</Label>
|
||||
</VirtualTableRowCell>
|
||||
</>
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,6 +42,8 @@ class SelectMovieRow extends Component {
|
||||
SelectMovieRow.propTypes = {
|
||||
id: PropTypes.number.isRequired,
|
||||
title: PropTypes.string.isRequired,
|
||||
tmdbId: PropTypes.number.isRequired,
|
||||
imdbId: PropTypes.string.isRequired,
|
||||
year: PropTypes.number.isRequired,
|
||||
onMovieSelect: PropTypes.func.isRequired
|
||||
};
|
||||
|
||||
@@ -3,6 +3,7 @@ import { useDispatch, useSelector } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import { Error } from 'App/State/AppSectionState';
|
||||
import AppState from 'App/State/AppState';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -130,7 +131,9 @@ function SelectQualityModalContent(props: SelectQualityModalContentProps) {
|
||||
{isFetching && <LoadingIndicator />}
|
||||
|
||||
{!isFetching && error ? (
|
||||
<div>{translate('UnableToLoadQualities')}</div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadQualities')}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{isPopulated && !error ? (
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import _ from 'lodash';
|
||||
import { connect } from 'react-redux';
|
||||
import { createSelector } from 'reselect';
|
||||
import createMovieSelector from 'Store/Selectors/createMovieSelector';
|
||||
@@ -10,15 +9,11 @@ function createMapStateToProps() {
|
||||
createMovieSelector(),
|
||||
createTagsSelector(),
|
||||
(movie, tagList) => {
|
||||
const tags = _.reduce(movie.tags, (acc, tag) => {
|
||||
const matchingTag = _.find(tagList, { id: tag });
|
||||
|
||||
if (matchingTag) {
|
||||
acc.push(matchingTag.label);
|
||||
}
|
||||
|
||||
return acc;
|
||||
}, []);
|
||||
const tags = movie.tags
|
||||
.map((tagId) => tagList.find((tag) => tag.id === tagId))
|
||||
.filter((tag) => !!tag)
|
||||
.map((tag) => tag.label)
|
||||
.sort((a, b) => a.localeCompare(b));
|
||||
|
||||
return {
|
||||
tags
|
||||
|
||||
@@ -10,6 +10,7 @@ import { SelectProvider } from 'App/SelectContext';
|
||||
import ClientSideCollectionAppState from 'App/State/ClientSideCollectionAppState';
|
||||
import MoviesAppState, { MovieIndexAppState } from 'App/State/MoviesAppState';
|
||||
import { RSS_SYNC } from 'Commands/commandNames';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import PageContent from 'Components/Page/PageContent';
|
||||
import PageContentBody from 'Components/Page/PageContentBody';
|
||||
@@ -20,12 +21,11 @@ import PageToolbarSection from 'Components/Page/Toolbar/PageToolbarSection';
|
||||
import PageToolbarSeparator from 'Components/Page/Toolbar/PageToolbarSeparator';
|
||||
import TableOptionsModalWrapper from 'Components/Table/TableOptions/TableOptionsModalWrapper';
|
||||
import withScrollPosition from 'Components/withScrollPosition';
|
||||
import { align, icons } from 'Helpers/Props';
|
||||
import { align, icons, kinds } from 'Helpers/Props';
|
||||
import SortDirection from 'Helpers/Props/SortDirection';
|
||||
import InteractiveImportModal from 'InteractiveImport/InteractiveImportModal';
|
||||
import NoMovie from 'Movie/NoMovie';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import { fetchMovies } from 'Store/Actions/movieActions';
|
||||
import {
|
||||
setMovieFilter,
|
||||
setMovieSort,
|
||||
@@ -105,7 +105,6 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
|
||||
const [isSelectMode, setIsSelectMode] = useState(false);
|
||||
|
||||
useEffect(() => {
|
||||
dispatch(fetchMovies());
|
||||
dispatch(fetchQueueDetails({ all: true }));
|
||||
}, [dispatch]);
|
||||
|
||||
@@ -339,7 +338,9 @@ const MovieIndex = withScrollPosition((props: MovieIndexProps) => {
|
||||
{isFetching && !isPopulated ? <LoadingIndicator /> : null}
|
||||
|
||||
{!isFetching && !!error ? (
|
||||
<div>{translate('UnableToLoadMovies')}</div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadMovies')}
|
||||
</Alert>
|
||||
) : null}
|
||||
|
||||
{isLoaded ? (
|
||||
|
||||
@@ -16,6 +16,7 @@ import MovieIndexPosterSelect from 'Movie/Index/Select/MovieIndexPosterSelect';
|
||||
import MoviePoster from 'Movie/MoviePoster';
|
||||
import { executeCommand } from 'Store/Actions/commandActions';
|
||||
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
|
||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import createMovieIndexItemSelector from '../createMovieIndexItemSelector';
|
||||
import MovieIndexPosterInfo from './MovieIndexPosterInfo';
|
||||
@@ -41,13 +42,13 @@ function MovieIndexPoster(props: MovieIndexPosterProps) {
|
||||
showTitle,
|
||||
showMonitored,
|
||||
showQualityProfile,
|
||||
showCinemaRelease,
|
||||
showReleaseDate,
|
||||
showSearchAction,
|
||||
} = useSelector(selectPosterOptions);
|
||||
|
||||
const { showRelativeDates, shortDateFormat, timeFormat } = useSelector(
|
||||
createUISettingsSelector()
|
||||
);
|
||||
const { showRelativeDates, shortDateFormat, longDateFormat, timeFormat } =
|
||||
useSelector(createUISettingsSelector());
|
||||
|
||||
const {
|
||||
title,
|
||||
@@ -59,12 +60,19 @@ function MovieIndexPoster(props: MovieIndexPosterProps) {
|
||||
youTubeTrailerId,
|
||||
hasFile,
|
||||
isAvailable,
|
||||
studio,
|
||||
added,
|
||||
year,
|
||||
inCinemas,
|
||||
physicalRelease,
|
||||
digitalRelease,
|
||||
path,
|
||||
movieFile,
|
||||
ratings,
|
||||
sizeOnDisk,
|
||||
certification,
|
||||
originalTitle,
|
||||
originalLanguage,
|
||||
} = movie;
|
||||
|
||||
const dispatch = useDispatch();
|
||||
@@ -122,9 +130,23 @@ function MovieIndexPoster(props: MovieIndexPosterProps) {
|
||||
height: `${posterHeight}px`,
|
||||
};
|
||||
|
||||
let releaseDate = '';
|
||||
let releaseDateType = '';
|
||||
if (physicalRelease && digitalRelease) {
|
||||
releaseDate =
|
||||
physicalRelease < digitalRelease ? physicalRelease : digitalRelease;
|
||||
releaseDateType = physicalRelease < digitalRelease ? 'Released' : 'Digital';
|
||||
} else if (physicalRelease && !digitalRelease) {
|
||||
releaseDate = physicalRelease;
|
||||
releaseDateType = 'Released';
|
||||
} else if (digitalRelease && !physicalRelease) {
|
||||
releaseDate = digitalRelease;
|
||||
releaseDateType = 'Digital';
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.content}>
|
||||
<div className={styles.posterContainer}>
|
||||
<div className={styles.posterContainer} title={title}>
|
||||
{isSelectMode ? <MovieIndexPosterSelect movieId={movieId} /> : null}
|
||||
|
||||
<Label className={styles.controls}>
|
||||
@@ -195,31 +217,68 @@ function MovieIndexPoster(props: MovieIndexPosterProps) {
|
||||
bottomRadius={false}
|
||||
/>
|
||||
|
||||
{showTitle ? <div className={styles.title}>{title}</div> : null}
|
||||
{showTitle ? (
|
||||
<div className={styles.title} title={title}>
|
||||
{title}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showMonitored ? (
|
||||
<div className={styles.title}>
|
||||
{monitored ? translate('monitored') : translate('unmonitored')}
|
||||
{monitored ? translate('Monitored') : translate('Unmonitored')}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showQualityProfile ? (
|
||||
<div className={styles.title}>{qualityProfile.name}</div>
|
||||
<div className={styles.title} title={translate('QualityProfile')}>
|
||||
{qualityProfile.name}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showCinemaRelease && inCinemas ? (
|
||||
<div className={styles.title} title={translate('InCinemas')}>
|
||||
<Icon name={icons.IN_CINEMAS} />{' '}
|
||||
{getRelativeDate(inCinemas, shortDateFormat, showRelativeDates, {
|
||||
timeFormat,
|
||||
timeForToday: false,
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
{showReleaseDate && releaseDate ? (
|
||||
<div className={styles.title}>
|
||||
<Icon
|
||||
name={releaseDateType === 'Digital' ? icons.MOVIE_FILE : icons.DISC}
|
||||
/>{' '}
|
||||
{getRelativeDate(releaseDate, shortDateFormat, showRelativeDates, {
|
||||
timeFormat,
|
||||
timeForToday: false,
|
||||
})}
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
<MovieIndexPosterInfo
|
||||
studio={studio}
|
||||
qualityProfile={qualityProfile}
|
||||
added={added}
|
||||
year={year}
|
||||
showQualityProfile={showQualityProfile}
|
||||
showCinemaRelease={showCinemaRelease}
|
||||
showReleaseDate={showReleaseDate}
|
||||
showRelativeDates={showRelativeDates}
|
||||
shortDateFormat={shortDateFormat}
|
||||
longDateFormat={longDateFormat}
|
||||
timeFormat={timeFormat}
|
||||
inCinemas={inCinemas}
|
||||
physicalRelease={physicalRelease}
|
||||
digitalRelease={digitalRelease}
|
||||
ratings={ratings}
|
||||
sizeOnDisk={sizeOnDisk}
|
||||
sortKey={sortKey}
|
||||
path={path}
|
||||
certification={certification}
|
||||
originalTitle={originalTitle}
|
||||
originalLanguage={originalLanguage}
|
||||
/>
|
||||
|
||||
<EditMovieModalConnector
|
||||
|
||||
@@ -3,3 +3,9 @@
|
||||
text-align: center;
|
||||
font-size: $smallFontSize;
|
||||
}
|
||||
|
||||
.title {
|
||||
@add-mixin truncate;
|
||||
|
||||
composes: info;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'info': string;
|
||||
'title': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
|
||||
@@ -1,6 +1,11 @@
|
||||
import React from 'react';
|
||||
import Icon from 'Components/Icon';
|
||||
import ImdbRating from 'Components/ImdbRating';
|
||||
import TmdbRating from 'Components/TmdbRating';
|
||||
import { icons } from 'Helpers/Props';
|
||||
import { Language, Ratings } from 'Movie/Movie';
|
||||
import QualityProfile from 'typings/QualityProfile';
|
||||
import formatDateTime from 'Utilities/Date/formatDateTime';
|
||||
import getRelativeDate from 'Utilities/Date/getRelativeDate';
|
||||
import formatBytes from 'Utilities/Number/formatBytes';
|
||||
import translate from 'Utilities/String/translate';
|
||||
@@ -9,19 +14,24 @@ import styles from './MovieIndexPosterInfo.css';
|
||||
interface MovieIndexPosterInfoProps {
|
||||
studio?: string;
|
||||
showQualityProfile: boolean;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
qualityProfile: any;
|
||||
qualityProfile: QualityProfile;
|
||||
added?: string;
|
||||
year: number;
|
||||
inCinemas?: string;
|
||||
digitalRelease?: string;
|
||||
physicalRelease?: string;
|
||||
path: string;
|
||||
ratings: Ratings;
|
||||
certification: string;
|
||||
originalTitle: string;
|
||||
originalLanguage: Language;
|
||||
sizeOnDisk?: number;
|
||||
sortKey: string;
|
||||
showRelativeDates: boolean;
|
||||
showCinemaRelease: boolean;
|
||||
showReleaseDate: boolean;
|
||||
shortDateFormat: string;
|
||||
longDateFormat: string;
|
||||
timeFormat: string;
|
||||
}
|
||||
|
||||
@@ -31,25 +41,39 @@ function MovieIndexPosterInfo(props: MovieIndexPosterInfoProps) {
|
||||
showQualityProfile,
|
||||
qualityProfile,
|
||||
added,
|
||||
year,
|
||||
inCinemas,
|
||||
digitalRelease,
|
||||
physicalRelease,
|
||||
path,
|
||||
ratings,
|
||||
certification,
|
||||
originalTitle,
|
||||
originalLanguage,
|
||||
sizeOnDisk,
|
||||
sortKey,
|
||||
showRelativeDates,
|
||||
showCinemaRelease,
|
||||
showReleaseDate,
|
||||
shortDateFormat,
|
||||
longDateFormat,
|
||||
timeFormat,
|
||||
} = props;
|
||||
|
||||
if (sortKey === 'studio' && studio) {
|
||||
return <div className={styles.info}>{studio}</div>;
|
||||
return (
|
||||
<div className={styles.info} title={translate('Studio')}>
|
||||
{studio}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'qualityProfileId' && !showQualityProfile) {
|
||||
return <div className={styles.info}>{qualityProfile.name}</div>;
|
||||
return (
|
||||
<div className={styles.info} title={translate('QualityProfile')}>
|
||||
{qualityProfile.name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'added' && added) {
|
||||
@@ -64,13 +88,24 @@ function MovieIndexPosterInfo(props: MovieIndexPosterInfoProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.info}>
|
||||
<div
|
||||
className={styles.info}
|
||||
title={formatDateTime(added, longDateFormat, timeFormat)}
|
||||
>
|
||||
{translate('Added')}: {addedDate}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'inCinemas' && inCinemas && !showReleaseDate) {
|
||||
if (sortKey === 'year' && year) {
|
||||
return (
|
||||
<div className={styles.info} title={translate('Year')}>
|
||||
{year}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'inCinemas' && inCinemas && !showCinemaRelease) {
|
||||
const inCinemasDate = getRelativeDate(
|
||||
inCinemas,
|
||||
shortDateFormat,
|
||||
@@ -82,7 +117,7 @@ function MovieIndexPosterInfo(props: MovieIndexPosterInfoProps) {
|
||||
);
|
||||
|
||||
return (
|
||||
<div className={styles.info}>
|
||||
<div className={styles.info} title={translate('InCinemas')}>
|
||||
<Icon name={icons.IN_CINEMAS} /> {inCinemasDate}
|
||||
</div>
|
||||
);
|
||||
@@ -124,18 +159,58 @@ function MovieIndexPosterInfo(props: MovieIndexPosterInfoProps) {
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'imdbRating' && !!ratings.imdb) {
|
||||
return (
|
||||
<div className={styles.info}>
|
||||
<ImdbRating ratings={ratings} iconSize={12} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'tmdbRating' && !!ratings.tmdb) {
|
||||
return (
|
||||
<div className={styles.info}>
|
||||
<TmdbRating ratings={ratings} iconSize={12} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'path') {
|
||||
return <div className={styles.info}>{path}</div>;
|
||||
return (
|
||||
<div className={styles.info} title={translate('Path')}>
|
||||
{path}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'sizeOnDisk') {
|
||||
return <div className={styles.info}>{formatBytes(sizeOnDisk)}</div>;
|
||||
return (
|
||||
<div className={styles.info} title={translate('SizeOnDisk')}>
|
||||
{formatBytes(sizeOnDisk)}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'certification') {
|
||||
return <div className={styles.info}>{certification}</div>;
|
||||
}
|
||||
|
||||
if (sortKey === 'originalTitle' && originalTitle) {
|
||||
return (
|
||||
<div className={styles.title} title={originalTitle}>
|
||||
{originalTitle}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
if (sortKey === 'originalLanguage' && originalLanguage) {
|
||||
return (
|
||||
<div className={styles.info} title={translate('OriginalLanguage')}>
|
||||
{originalLanguage.name}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -143,6 +143,7 @@ export default function MovieIndexPosters(props: MovieIndexPostersProps) {
|
||||
showTitle,
|
||||
showMonitored,
|
||||
showQualityProfile,
|
||||
showCinemaRelease,
|
||||
showReleaseDate,
|
||||
} = posterOptions;
|
||||
|
||||
@@ -167,6 +168,10 @@ export default function MovieIndexPosters(props: MovieIndexPostersProps) {
|
||||
heights.push(19);
|
||||
}
|
||||
|
||||
if (showCinemaRelease) {
|
||||
heights.push(19);
|
||||
}
|
||||
|
||||
if (showReleaseDate) {
|
||||
heights.push(19);
|
||||
}
|
||||
@@ -174,8 +179,13 @@ export default function MovieIndexPosters(props: MovieIndexPostersProps) {
|
||||
switch (sortKey) {
|
||||
case 'studio':
|
||||
case 'added':
|
||||
case 'year':
|
||||
case 'imdbRating':
|
||||
case 'tmdbRating':
|
||||
case 'path':
|
||||
case 'sizeOnDisk':
|
||||
case 'originalTitle':
|
||||
case 'originalLanguage':
|
||||
heights.push(19);
|
||||
break;
|
||||
case 'qualityProfileId':
|
||||
@@ -183,6 +193,17 @@ export default function MovieIndexPosters(props: MovieIndexPostersProps) {
|
||||
heights.push(19);
|
||||
}
|
||||
break;
|
||||
case 'inCinemas':
|
||||
if (!showCinemaRelease) {
|
||||
heights.push(19);
|
||||
}
|
||||
break;
|
||||
case 'digitalRelease':
|
||||
case 'physicalRelease':
|
||||
if (!showReleaseDate) {
|
||||
heights.push(19);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// No need to add a height of 0
|
||||
}
|
||||
|
||||
@@ -16,6 +16,13 @@ export interface Collection {
|
||||
title: string;
|
||||
}
|
||||
|
||||
export interface Ratings {
|
||||
imdb: object;
|
||||
tmdb: object;
|
||||
metacritic: object;
|
||||
rottenTomatoes: object;
|
||||
}
|
||||
|
||||
interface Movie extends ModelBase {
|
||||
tmdbId: number;
|
||||
imdbId: string;
|
||||
@@ -41,7 +48,7 @@ interface Movie extends ModelBase {
|
||||
path: string;
|
||||
sizeOnDisk: number;
|
||||
genres: string[];
|
||||
ratings: object;
|
||||
ratings: Ratings;
|
||||
certification: string;
|
||||
tags: number[];
|
||||
images: Image[];
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -109,9 +110,9 @@ class FileEditModalContent extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadQualities')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -92,9 +93,9 @@ class SelectQualityModalContent extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadQualities')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import RootFolderRowConnector from './RootFolderRowConnector';
|
||||
|
||||
@@ -44,9 +46,9 @@ function RootFolders(props) {
|
||||
|
||||
if (!isFetching && !!error) {
|
||||
return (
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadRootFolders')}
|
||||
</div>
|
||||
</Alert>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@ import styles from './AdvancedSettingsButton.css';
|
||||
function AdvancedSettingsButton(props) {
|
||||
const {
|
||||
advancedSettings,
|
||||
onAdvancedSettingsPress
|
||||
onAdvancedSettingsPress,
|
||||
showLabel
|
||||
} = props;
|
||||
|
||||
return (
|
||||
@@ -43,18 +44,27 @@ function AdvancedSettingsButton(props) {
|
||||
/>
|
||||
</span>
|
||||
|
||||
<div className={styles.labelContainer}>
|
||||
<div className={styles.label}>
|
||||
{advancedSettings ? translate('HideAdvanced') : translate('ShowAdvanced')}
|
||||
</div>
|
||||
</div>
|
||||
{
|
||||
showLabel ?
|
||||
<div className={styles.labelContainer}>
|
||||
<div className={styles.label}>
|
||||
{advancedSettings ? translate('HideAdvanced') : translate('ShowAdvanced')}
|
||||
</div>
|
||||
</div> :
|
||||
null
|
||||
}
|
||||
</Link>
|
||||
);
|
||||
}
|
||||
|
||||
AdvancedSettingsButton.propTypes = {
|
||||
advancedSettings: PropTypes.bool.isRequired,
|
||||
onAdvancedSettingsPress: PropTypes.func.isRequired
|
||||
onAdvancedSettingsPress: PropTypes.func.isRequired,
|
||||
showLabel: PropTypes.bool.isRequired
|
||||
};
|
||||
|
||||
AdvancedSettingsButton.defaultProps = {
|
||||
showLabel: true
|
||||
};
|
||||
|
||||
export default AdvancedSettingsButton;
|
||||
|
||||
@@ -155,7 +155,7 @@ class CustomFormat extends Component {
|
||||
message={
|
||||
<div>
|
||||
<div>
|
||||
{translate('AreYouSureYouWantToDeleteFormat', [name])}
|
||||
{translate('DeleteCustomFormatMessageText', [name])}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Button from 'Components/Link/Button';
|
||||
import ClipboardButton from 'Components/Link/ClipboardButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
@@ -41,9 +42,9 @@ class ExportCustomFormatModalContent extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadCustomFormats')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
@@ -11,7 +12,7 @@ import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes, sizes } from 'Helpers/Props';
|
||||
import { inputTypes, kinds, sizes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './ImportCustomFormatModalContent.css';
|
||||
|
||||
@@ -95,9 +96,9 @@ class ImportCustomFormatModalContent extends Component {
|
||||
|
||||
{
|
||||
!isFetching && !!error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadCustomFormats')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -78,7 +78,7 @@ class Specification extends Component {
|
||||
|
||||
<IconButton
|
||||
className={styles.cloneButton}
|
||||
title={translate('CloneFormatTag')}
|
||||
title={translate('CloneCondition')}
|
||||
name={icons.CLONE}
|
||||
onPress={this.onCloneSpecificationPress}
|
||||
/>
|
||||
@@ -114,14 +114,8 @@ class Specification extends Component {
|
||||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteSpecificationModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteCustomFormat')}
|
||||
message={
|
||||
<div>
|
||||
<div>
|
||||
{translate('AreYouSureYouWantToDeleteFormat', [name])}
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
title={translate('DeleteCondition')}
|
||||
message={translate('DeleteConditionMessageText', [name])}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteSpecification}
|
||||
onCancel={this.onDeleteSpecificationModalClose}
|
||||
|
||||
@@ -8,6 +8,7 @@ import { icons } from 'Helpers/Props';
|
||||
import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import DownloadClientsConnector from './DownloadClients/DownloadClientsConnector';
|
||||
import ManageDownloadClientsModal from './DownloadClients/Manage/ManageDownloadClientsModal';
|
||||
import DownloadClientOptionsConnector from './Options/DownloadClientOptionsConnector';
|
||||
import RemotePathMappingsConnector from './RemotePathMappings/RemotePathMappingsConnector';
|
||||
|
||||
@@ -23,7 +24,8 @@ class DownloadClientSettings extends Component {
|
||||
|
||||
this.state = {
|
||||
isSaving: false,
|
||||
hasPendingChanges: false
|
||||
hasPendingChanges: false,
|
||||
isManageDownloadClientsOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +40,14 @@ class DownloadClientSettings extends Component {
|
||||
this.setState(payload);
|
||||
};
|
||||
|
||||
onManageDownloadClientsPress = () => {
|
||||
this.setState({ isManageDownloadClientsOpen: true });
|
||||
};
|
||||
|
||||
onManageDownloadClientsModalClose = () => {
|
||||
this.setState({ isManageDownloadClientsOpen: false });
|
||||
};
|
||||
|
||||
onSavePress = () => {
|
||||
if (this._saveCallback) {
|
||||
this._saveCallback();
|
||||
@@ -55,7 +65,8 @@ class DownloadClientSettings extends Component {
|
||||
|
||||
const {
|
||||
isSaving,
|
||||
hasPendingChanges
|
||||
hasPendingChanges,
|
||||
isManageDownloadClientsOpen
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
@@ -73,6 +84,12 @@ class DownloadClientSettings extends Component {
|
||||
isSpinning={isTestingAll}
|
||||
onPress={dispatchTestAllDownloadClients}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Manage Clients"
|
||||
iconName={icons.MANAGE}
|
||||
onPress={this.onManageDownloadClientsPress}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
onSavePress={this.onSavePress}
|
||||
@@ -87,6 +104,11 @@ class DownloadClientSettings extends Component {
|
||||
/>
|
||||
|
||||
<RemotePathMappingsConnector />
|
||||
|
||||
<ManageDownloadClientsModal
|
||||
isOpen={isManageDownloadClientsOpen}
|
||||
onModalClose={this.onManageDownloadClientsModalClose}
|
||||
/>
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ManageDownloadClientsEditModalContent from './ManageDownloadClientsEditModalContent';
|
||||
|
||||
interface ManageDownloadClientsEditModalProps {
|
||||
isOpen: boolean;
|
||||
downloadClientIds: number[];
|
||||
onSavePress(payload: object): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function ManageDownloadClientsEditModal(
|
||||
props: ManageDownloadClientsEditModalProps
|
||||
) {
|
||||
const { isOpen, downloadClientIds, onSavePress, onModalClose } = props;
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<ManageDownloadClientsEditModalContent
|
||||
downloadClientIds={downloadClientIds}
|
||||
onSavePress={onSavePress}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageDownloadClientsEditModal;
|
||||
@@ -0,0 +1,16 @@
|
||||
.modalFooter {
|
||||
composes: modalFooter from '~Components/Modal/ModalFooter.css';
|
||||
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointExtraSmall) {
|
||||
.modalFooter {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'modalFooter': string;
|
||||
'selected': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,180 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './ManageDownloadClientsEditModalContent.css';
|
||||
|
||||
interface SavePayload {
|
||||
enable?: boolean;
|
||||
removeCompletedDownloads?: boolean;
|
||||
removeFailedDownloads?: boolean;
|
||||
priority?: number;
|
||||
}
|
||||
|
||||
interface ManageDownloadClientsEditModalContentProps {
|
||||
downloadClientIds: number[];
|
||||
onSavePress(payload: object): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const enableOptions = [
|
||||
{ key: NO_CHANGE, value: 'No Change', disabled: true },
|
||||
{ key: 'enabled', value: 'Enabled' },
|
||||
{ key: 'disabled', value: 'Disabled' },
|
||||
];
|
||||
|
||||
function ManageDownloadClientsEditModalContent(
|
||||
props: ManageDownloadClientsEditModalContentProps
|
||||
) {
|
||||
const { downloadClientIds, onSavePress, onModalClose } = props;
|
||||
|
||||
const [enable, setEnable] = useState(NO_CHANGE);
|
||||
const [removeCompletedDownloads, setRemoveCompletedDownloads] =
|
||||
useState(NO_CHANGE);
|
||||
const [removeFailedDownloads, setRemoveFailedDownloads] = useState(NO_CHANGE);
|
||||
const [priority, setPriority] = useState<null | string | number>(null);
|
||||
|
||||
const save = useCallback(() => {
|
||||
let hasChanges = false;
|
||||
const payload: SavePayload = {};
|
||||
|
||||
if (enable !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.enable = enable === 'enabled';
|
||||
}
|
||||
|
||||
if (removeCompletedDownloads !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.removeCompletedDownloads = removeCompletedDownloads === 'enabled';
|
||||
}
|
||||
|
||||
if (removeFailedDownloads !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.removeFailedDownloads = removeFailedDownloads === 'enabled';
|
||||
}
|
||||
|
||||
if (priority !== null) {
|
||||
hasChanges = true;
|
||||
payload.priority = priority as number;
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
onSavePress(payload);
|
||||
}
|
||||
|
||||
onModalClose();
|
||||
}, [
|
||||
enable,
|
||||
priority,
|
||||
removeCompletedDownloads,
|
||||
removeFailedDownloads,
|
||||
onSavePress,
|
||||
onModalClose,
|
||||
]);
|
||||
|
||||
const onInputChange = useCallback(
|
||||
({ name, value }: { name: string; value: string }) => {
|
||||
switch (name) {
|
||||
case 'enable':
|
||||
setEnable(value);
|
||||
break;
|
||||
case 'priority':
|
||||
setPriority(value);
|
||||
break;
|
||||
case 'removeCompletedDownloads':
|
||||
setRemoveCompletedDownloads(value);
|
||||
break;
|
||||
case 'removeFailedDownloads':
|
||||
setRemoveFailedDownloads(value);
|
||||
break;
|
||||
default:
|
||||
console.warn('EditDownloadClientsModalContent Unknown Input');
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const selectedCount = downloadClientIds.length;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>{translate('EditSelectedDownloadClients')}</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Enabled')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="enable"
|
||||
value={enable}
|
||||
values={enableOptions}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('Priority')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.NUMBER}
|
||||
name="priority"
|
||||
value={priority}
|
||||
min={1}
|
||||
max={50}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveCompletedDownloads')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="removeCompletedDownloads"
|
||||
value={removeCompletedDownloads}
|
||||
values={enableOptions}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RemoveFailedDownloads')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="removeFailedDownloads"
|
||||
value={removeFailedDownloads}
|
||||
values={enableOptions}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter className={styles.modalFooter}>
|
||||
<div className={styles.selected}>
|
||||
{translate('{count} download clients selected', {
|
||||
count: selectedCount,
|
||||
})}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||
|
||||
<Button onPress={save}>{translate('Apply Changes')}</Button>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageDownloadClientsEditModalContent;
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ManageDownloadClientsModalContent from './ManageDownloadClientsModalContent';
|
||||
|
||||
interface ManageDownloadClientsModalProps {
|
||||
isOpen: boolean;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function ManageDownloadClientsModal(props: ManageDownloadClientsModalProps) {
|
||||
const { isOpen, onModalClose } = props;
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<ManageDownloadClientsModalContent onModalClose={onModalClose} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageDownloadClientsModal;
|
||||
@@ -0,0 +1,16 @@
|
||||
.leftButtons,
|
||||
.rightButtons {
|
||||
display: flex;
|
||||
flex: 1 0 50%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.rightButtons {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
composes: button from '~Components/Link/Button.css';
|
||||
|
||||
margin-right: 10px;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'deleteButton': string;
|
||||
'leftButtons': string;
|
||||
'rightButtons': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,241 @@
|
||||
import React, { useCallback, useMemo, useState } from 'react';
|
||||
import { useDispatch, useSelector } from 'react-redux';
|
||||
import { DownloadClientAppState } from 'App/State/SettingsAppState';
|
||||
import Button from 'Components/Link/Button';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import Table from 'Components/Table/Table';
|
||||
import TableBody from 'Components/Table/TableBody';
|
||||
import useSelectState from 'Helpers/Hooks/useSelectState';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
import {
|
||||
bulkDeleteDownloadClients,
|
||||
bulkEditDownloadClients,
|
||||
} from 'Store/Actions/settingsActions';
|
||||
import createClientSideCollectionSelector from 'Store/Selectors/createClientSideCollectionSelector';
|
||||
import { SelectStateInputProps } from 'typings/props';
|
||||
import getErrorMessage from 'Utilities/Object/getErrorMessage';
|
||||
import getSelectedIds from 'Utilities/Table/getSelectedIds';
|
||||
import ManageDownloadClientsEditModal from './Edit/ManageDownloadClientsEditModal';
|
||||
import ManageDownloadClientsModalRow from './ManageDownloadClientsModalRow';
|
||||
import styles from './ManageDownloadClientsModalContent.css';
|
||||
|
||||
// TODO: This feels janky to do, but not sure of a better way currently
|
||||
type OnSelectedChangeCallback = React.ComponentProps<
|
||||
typeof ManageDownloadClientsModalRow
|
||||
>['onSelectedChange'];
|
||||
|
||||
const COLUMNS = [
|
||||
{
|
||||
name: 'name',
|
||||
label: 'Name',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'implementation',
|
||||
label: 'Implementation',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'enable',
|
||||
label: 'Enabled',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'priority',
|
||||
label: 'Priority',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'removeCompletedDownloads',
|
||||
label: 'Remove Completed',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
{
|
||||
name: 'removeFailedDownloads',
|
||||
label: 'Remove Failed',
|
||||
isSortable: true,
|
||||
isVisible: true,
|
||||
},
|
||||
];
|
||||
|
||||
interface ManageDownloadClientsModalContentProps {
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function ManageDownloadClientsModalContent(
|
||||
props: ManageDownloadClientsModalContentProps
|
||||
) {
|
||||
const { onModalClose } = props;
|
||||
|
||||
const {
|
||||
isFetching,
|
||||
isPopulated,
|
||||
isDeleting,
|
||||
isSaving,
|
||||
error,
|
||||
items,
|
||||
}: DownloadClientAppState = useSelector(
|
||||
createClientSideCollectionSelector('settings.downloadClients')
|
||||
);
|
||||
const dispatch = useDispatch();
|
||||
|
||||
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
|
||||
const [isEditModalOpen, setIsEditModalOpen] = useState(false);
|
||||
|
||||
const [selectState, setSelectState] = useSelectState();
|
||||
|
||||
const { allSelected, allUnselected, selectedState } = selectState;
|
||||
|
||||
const selectedIds: number[] = useMemo(() => {
|
||||
return getSelectedIds(selectedState);
|
||||
}, [selectedState]);
|
||||
|
||||
const selectedCount = selectedIds.length;
|
||||
|
||||
const onDeletePress = useCallback(() => {
|
||||
setIsDeleteModalOpen(true);
|
||||
}, [setIsDeleteModalOpen]);
|
||||
|
||||
const onDeleteModalClose = useCallback(() => {
|
||||
setIsDeleteModalOpen(false);
|
||||
}, [setIsDeleteModalOpen]);
|
||||
|
||||
const onEditPress = useCallback(() => {
|
||||
setIsEditModalOpen(true);
|
||||
}, [setIsEditModalOpen]);
|
||||
|
||||
const onEditModalClose = useCallback(() => {
|
||||
setIsEditModalOpen(false);
|
||||
}, [setIsEditModalOpen]);
|
||||
|
||||
const onConfirmDelete = useCallback(() => {
|
||||
dispatch(bulkDeleteDownloadClients({ ids: selectedIds }));
|
||||
setIsDeleteModalOpen(false);
|
||||
}, [selectedIds, dispatch]);
|
||||
|
||||
const onSavePress = useCallback(
|
||||
(payload: object) => {
|
||||
setIsEditModalOpen(false);
|
||||
|
||||
dispatch(
|
||||
bulkEditDownloadClients({
|
||||
ids: selectedIds,
|
||||
...payload,
|
||||
})
|
||||
);
|
||||
},
|
||||
[selectedIds, dispatch]
|
||||
);
|
||||
|
||||
const onSelectAllChange = useCallback(
|
||||
({ value }: SelectStateInputProps) => {
|
||||
setSelectState({ type: value ? 'selectAll' : 'unselectAll', items });
|
||||
},
|
||||
[items, setSelectState]
|
||||
);
|
||||
|
||||
const onSelectedChange = useCallback<OnSelectedChangeCallback>(
|
||||
({ id, value, shiftKey = false }) => {
|
||||
setSelectState({
|
||||
type: 'toggleSelected',
|
||||
items,
|
||||
id,
|
||||
isSelected: value,
|
||||
shiftKey,
|
||||
});
|
||||
},
|
||||
[items, setSelectState]
|
||||
);
|
||||
|
||||
const errorMessage = getErrorMessage(error, 'Unable to load import lists.');
|
||||
const anySelected = selectedCount > 0;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>Manage Import Lists</ModalHeader>
|
||||
<ModalBody>
|
||||
{isFetching ? <LoadingIndicator /> : null}
|
||||
|
||||
{error ? <div>{errorMessage}</div> : null}
|
||||
|
||||
{isPopulated && !!items.length && !isFetching && !isFetching ? (
|
||||
<Table
|
||||
columns={COLUMNS}
|
||||
horizontalScroll={true}
|
||||
selectAll={true}
|
||||
allSelected={allSelected}
|
||||
allUnselected={allUnselected}
|
||||
onSelectAllChange={onSelectAllChange}
|
||||
>
|
||||
<TableBody>
|
||||
{items.map((item) => {
|
||||
return (
|
||||
<ManageDownloadClientsModalRow
|
||||
key={item.id}
|
||||
isSelected={selectedState[item.id]}
|
||||
{...item}
|
||||
columns={COLUMNS}
|
||||
onSelectedChange={onSelectedChange}
|
||||
/>
|
||||
);
|
||||
})}
|
||||
</TableBody>
|
||||
</Table>
|
||||
) : null}
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter>
|
||||
<div className={styles.leftButtons}>
|
||||
<SpinnerButton
|
||||
kind={kinds.DANGER}
|
||||
isSpinning={isDeleting}
|
||||
isDisabled={!anySelected}
|
||||
onPress={onDeletePress}
|
||||
>
|
||||
Delete
|
||||
</SpinnerButton>
|
||||
|
||||
<SpinnerButton
|
||||
isSpinning={isSaving}
|
||||
isDisabled={!anySelected}
|
||||
onPress={onEditPress}
|
||||
>
|
||||
Edit
|
||||
</SpinnerButton>
|
||||
</div>
|
||||
|
||||
<Button onPress={onModalClose}>Close</Button>
|
||||
</ModalFooter>
|
||||
|
||||
<ManageDownloadClientsEditModal
|
||||
isOpen={isEditModalOpen}
|
||||
onModalClose={onEditModalClose}
|
||||
onSavePress={onSavePress}
|
||||
downloadClientIds={selectedIds}
|
||||
/>
|
||||
|
||||
<ConfirmModal
|
||||
isOpen={isDeleteModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title="Delete Download Clients(s)"
|
||||
message={`Are you sure you want to delete ${selectedIds.length} download clients(s)?`}
|
||||
confirmLabel="Delete"
|
||||
onConfirm={onConfirmDelete}
|
||||
onCancel={onDeleteModalClose}
|
||||
/>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageDownloadClientsModalContent;
|
||||
@@ -0,0 +1,11 @@
|
||||
.name,
|
||||
.enable,
|
||||
.tags,
|
||||
.priority,
|
||||
.removeCompletedDownloads,
|
||||
.removeFailedDownloads,
|
||||
.implementation {
|
||||
composes: cell from '~Components/Table/Cells/TableRowCell.css';
|
||||
|
||||
word-break: break-all;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'enable': string;
|
||||
'implementation': string;
|
||||
'name': string;
|
||||
'priority': string;
|
||||
'removeCompletedDownloads': string;
|
||||
'removeFailedDownloads': string;
|
||||
'tags': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,77 @@
|
||||
import React, { useCallback } from 'react';
|
||||
import TableRowCell from 'Components/Table/Cells/TableRowCell';
|
||||
import TableSelectCell from 'Components/Table/Cells/TableSelectCell';
|
||||
import Column from 'Components/Table/Column';
|
||||
import TableRow from 'Components/Table/TableRow';
|
||||
import { SelectStateInputProps } from 'typings/props';
|
||||
import styles from './ManageDownloadClientsModalRow.css';
|
||||
|
||||
interface ManageDownloadClientsModalRowProps {
|
||||
id: number;
|
||||
name: string;
|
||||
enable: boolean;
|
||||
priority: number;
|
||||
removeCompletedDownloads: boolean;
|
||||
removeFailedDownloads: boolean;
|
||||
implementation: string;
|
||||
columns: Column[];
|
||||
isSelected?: boolean;
|
||||
onSelectedChange(result: SelectStateInputProps): void;
|
||||
}
|
||||
|
||||
function ManageDownloadClientsModalRow(
|
||||
props: ManageDownloadClientsModalRowProps
|
||||
) {
|
||||
const {
|
||||
id,
|
||||
isSelected,
|
||||
name,
|
||||
enable,
|
||||
priority,
|
||||
removeCompletedDownloads,
|
||||
removeFailedDownloads,
|
||||
implementation,
|
||||
onSelectedChange,
|
||||
} = props;
|
||||
|
||||
const onSelectedChangeWrapper = useCallback(
|
||||
(result: SelectStateInputProps) => {
|
||||
onSelectedChange({
|
||||
...result,
|
||||
});
|
||||
},
|
||||
[onSelectedChange]
|
||||
);
|
||||
|
||||
return (
|
||||
<TableRow>
|
||||
<TableSelectCell
|
||||
id={id}
|
||||
isSelected={isSelected}
|
||||
onSelectedChange={onSelectedChangeWrapper}
|
||||
/>
|
||||
|
||||
<TableRowCell className={styles.name}>{name}</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.implementation}>
|
||||
{implementation}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.enable}>
|
||||
{enable ? 'Yes' : 'No'}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.priority}>{priority}</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.removeCompletedDownloads}>
|
||||
{removeCompletedDownloads ? 'Yes' : 'No'}
|
||||
</TableRowCell>
|
||||
|
||||
<TableRowCell className={styles.removeFailedDownloads}>
|
||||
{removeFailedDownloads ? 'Yes' : 'No'}
|
||||
</TableRowCell>
|
||||
</TableRow>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageDownloadClientsModalRow;
|
||||
@@ -29,9 +29,9 @@ function DownloadClientOptions(props) {
|
||||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadDownloadClientOptions')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -88,8 +88,8 @@ class RemotePathMapping extends Component {
|
||||
<ConfirmModal
|
||||
isOpen={this.state.isDeleteRemotePathMappingModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteDelayProfile')}
|
||||
message={translate('AreYouSureYouWantToDeleteThisRemotePathMapping')}
|
||||
title={translate('DeleteRemotePathMapping')}
|
||||
message={translate('DeleteRemotePathMappingMessageText')}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteRemotePathMapping}
|
||||
onCancel={this.onDeleteRemotePathMappingModalClose}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import PropTypes from 'prop-types';
|
||||
import React, { Component } from 'react';
|
||||
import Alert from 'Components/Alert';
|
||||
import Form from 'Components/Form/Form';
|
||||
import LoadingIndicator from 'Components/Loading/LoadingIndicator';
|
||||
import ConfirmModal from 'Components/Modal/ConfirmModal';
|
||||
@@ -123,9 +124,9 @@ class GeneralSettings extends Component {
|
||||
|
||||
{
|
||||
!isFetching && error &&
|
||||
<div>
|
||||
<Alert kind={kinds.DANGER}>
|
||||
{translate('UnableToLoadGeneralSettings')}
|
||||
</div>
|
||||
</Alert>
|
||||
}
|
||||
|
||||
{
|
||||
|
||||
@@ -168,7 +168,7 @@ class SecuritySettings extends Component {
|
||||
isOpen={this.state.isConfirmApiKeyResetModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('ResetAPIKey')}
|
||||
message={translate('AreYouSureYouWantToResetYourAPIKey')}
|
||||
message={translate('ResetAPIKeyMessageText')}
|
||||
confirmLabel={translate('Reset')}
|
||||
onConfirm={this.onConfirmResetApiKey}
|
||||
onCancel={this.onCloseResetApiKeyModal}
|
||||
|
||||
@@ -89,7 +89,7 @@ class ImportListExclusion extends Component {
|
||||
isOpen={this.state.isDeleteImportExclusionModalOpen}
|
||||
kind={kinds.DANGER}
|
||||
title={translate('DeleteImportListExclusion')}
|
||||
message={translate('AreYouSureYouWantToDeleteThisImportListExclusion')}
|
||||
message={translate('DeleteImportListExclusionMessageText')}
|
||||
confirmLabel={translate('Delete')}
|
||||
onConfirm={this.onConfirmDeleteImportExclusion}
|
||||
onCancel={this.onDeleteImportExclusionModalClose}
|
||||
|
||||
@@ -9,6 +9,7 @@ import SettingsToolbarConnector from 'Settings/SettingsToolbarConnector';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import ImportListExclusionsConnector from './ImportListExclusions/ImportListExclusionsConnector';
|
||||
import ImportListsConnector from './ImportLists/ImportListsConnector';
|
||||
import ManageImportListsModal from './ImportLists/Manage/ManageImportListsModal';
|
||||
import ImportListOptionsConnector from './Options/ImportListOptionsConnector';
|
||||
|
||||
class ImportListSettings extends Component {
|
||||
@@ -23,7 +24,8 @@ class ImportListSettings extends Component {
|
||||
|
||||
this.state = {
|
||||
isSaving: false,
|
||||
hasPendingChanges: false
|
||||
hasPendingChanges: false,
|
||||
isManageImportListsOpen: false
|
||||
};
|
||||
}
|
||||
|
||||
@@ -38,6 +40,14 @@ class ImportListSettings extends Component {
|
||||
this.setState(payload);
|
||||
};
|
||||
|
||||
onManageImportListsPress = () => {
|
||||
this.setState({ isManageImportListsOpen: true });
|
||||
};
|
||||
|
||||
onManageImportListsModalClose = () => {
|
||||
this.setState({ isManageImportListsOpen: false });
|
||||
};
|
||||
|
||||
onSavePress = () => {
|
||||
if (this._saveCallback) {
|
||||
this._saveCallback();
|
||||
@@ -55,7 +65,8 @@ class ImportListSettings extends Component {
|
||||
|
||||
const {
|
||||
isSaving,
|
||||
hasPendingChanges
|
||||
hasPendingChanges,
|
||||
isManageImportListsOpen
|
||||
} = this.state;
|
||||
|
||||
return (
|
||||
@@ -73,6 +84,12 @@ class ImportListSettings extends Component {
|
||||
isSpinning={isTestingAll}
|
||||
onPress={dispatchTestAllImportList}
|
||||
/>
|
||||
|
||||
<PageToolbarButton
|
||||
label="Manage Lists"
|
||||
iconName={icons.MANAGE}
|
||||
onPress={this.onManageImportListsPress}
|
||||
/>
|
||||
</Fragment>
|
||||
}
|
||||
onSavePress={this.onSavePress}
|
||||
@@ -88,6 +105,11 @@ class ImportListSettings extends Component {
|
||||
|
||||
<ImportListExclusionsConnector />
|
||||
|
||||
<ManageImportListsModal
|
||||
isOpen={isManageImportListsOpen}
|
||||
onModalClose={this.onManageImportListsModalClose}
|
||||
/>
|
||||
|
||||
</PageContentBody>
|
||||
</PageContent>
|
||||
);
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ManageImportListsEditModalContent from './ManageImportListsEditModalContent';
|
||||
|
||||
interface ManageImportListsEditModalProps {
|
||||
isOpen: boolean;
|
||||
importListIds: number[];
|
||||
onSavePress(payload: object): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function ManageImportListsEditModal(props: ManageImportListsEditModalProps) {
|
||||
const { isOpen, importListIds, onSavePress, onModalClose } = props;
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<ManageImportListsEditModalContent
|
||||
importListIds={importListIds}
|
||||
onSavePress={onSavePress}
|
||||
onModalClose={onModalClose}
|
||||
/>
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageImportListsEditModal;
|
||||
@@ -0,0 +1,16 @@
|
||||
.modalFooter {
|
||||
composes: modalFooter from '~Components/Modal/ModalFooter.css';
|
||||
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.selected {
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@media only screen and (max-width: $breakpointExtraSmall) {
|
||||
.modalFooter {
|
||||
flex-direction: column;
|
||||
gap: 10px;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
// This file is automatically generated.
|
||||
// Please do not change this file!
|
||||
interface CssExports {
|
||||
'modalFooter': string;
|
||||
'selected': string;
|
||||
}
|
||||
export const cssExports: CssExports;
|
||||
export default cssExports;
|
||||
@@ -0,0 +1,152 @@
|
||||
import React, { useCallback, useState } from 'react';
|
||||
import FormGroup from 'Components/Form/FormGroup';
|
||||
import FormInputGroup from 'Components/Form/FormInputGroup';
|
||||
import FormLabel from 'Components/Form/FormLabel';
|
||||
import Button from 'Components/Link/Button';
|
||||
import ModalBody from 'Components/Modal/ModalBody';
|
||||
import ModalContent from 'Components/Modal/ModalContent';
|
||||
import ModalFooter from 'Components/Modal/ModalFooter';
|
||||
import ModalHeader from 'Components/Modal/ModalHeader';
|
||||
import { inputTypes } from 'Helpers/Props';
|
||||
import translate from 'Utilities/String/translate';
|
||||
import styles from './ManageImportListsEditModalContent.css';
|
||||
|
||||
interface SavePayload {
|
||||
enableAuto?: boolean;
|
||||
qualityProfileId?: number;
|
||||
rootFolderPath?: string;
|
||||
}
|
||||
|
||||
interface ManageImportListsEditModalContentProps {
|
||||
importListIds: number[];
|
||||
onSavePress(payload: object): void;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
const NO_CHANGE = 'noChange';
|
||||
|
||||
const autoAddOptions = [
|
||||
{ key: NO_CHANGE, value: 'No Change', disabled: true },
|
||||
{ key: 'enabled', value: 'Enabled' },
|
||||
{ key: 'disabled', value: 'Disabled' },
|
||||
];
|
||||
|
||||
function ManageImportListsEditModalContent(
|
||||
props: ManageImportListsEditModalContentProps
|
||||
) {
|
||||
const { importListIds, onSavePress, onModalClose } = props;
|
||||
|
||||
const [enableAuto, setenableAuto] = useState(NO_CHANGE);
|
||||
const [qualityProfileId, setQualityProfileId] = useState<string | number>(
|
||||
NO_CHANGE
|
||||
);
|
||||
const [rootFolderPath, setRootFolderPath] = useState(NO_CHANGE);
|
||||
|
||||
const save = useCallback(() => {
|
||||
let hasChanges = false;
|
||||
const payload: SavePayload = {};
|
||||
|
||||
if (enableAuto !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.enableAuto = enableAuto === 'enabled';
|
||||
}
|
||||
|
||||
if (qualityProfileId !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.qualityProfileId = qualityProfileId as number;
|
||||
}
|
||||
|
||||
if (rootFolderPath !== NO_CHANGE) {
|
||||
hasChanges = true;
|
||||
payload.rootFolderPath = rootFolderPath;
|
||||
}
|
||||
|
||||
if (hasChanges) {
|
||||
onSavePress(payload);
|
||||
}
|
||||
|
||||
onModalClose();
|
||||
}, [enableAuto, qualityProfileId, rootFolderPath, onSavePress, onModalClose]);
|
||||
|
||||
const onInputChange = useCallback(
|
||||
({ name, value }: { name: string; value: string }) => {
|
||||
switch (name) {
|
||||
case 'enableAuto':
|
||||
setenableAuto(value);
|
||||
break;
|
||||
case 'qualityProfileId':
|
||||
setQualityProfileId(value);
|
||||
break;
|
||||
case 'rootFolderPath':
|
||||
setRootFolderPath(value);
|
||||
break;
|
||||
default:
|
||||
console.warn('EditImportListModalContent Unknown Input');
|
||||
}
|
||||
},
|
||||
[]
|
||||
);
|
||||
|
||||
const selectedCount = importListIds.length;
|
||||
|
||||
return (
|
||||
<ModalContent onModalClose={onModalClose}>
|
||||
<ModalHeader>{translate('EditSelectedImportLists')}</ModalHeader>
|
||||
|
||||
<ModalBody>
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('AutomaticAdd')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.SELECT}
|
||||
name="enableAuto"
|
||||
value={enableAuto}
|
||||
values={autoAddOptions}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('QualityProfile')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.QUALITY_PROFILE_SELECT}
|
||||
name="qualityProfileId"
|
||||
value={qualityProfileId}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
|
||||
<FormGroup>
|
||||
<FormLabel>{translate('RootFolder')}</FormLabel>
|
||||
|
||||
<FormInputGroup
|
||||
type={inputTypes.ROOT_FOLDER_SELECT}
|
||||
name="rootFolderPath"
|
||||
value={rootFolderPath}
|
||||
includeNoChange={true}
|
||||
includeNoChangeDisabled={false}
|
||||
selectedValueOptions={{ includeFreeSpace: false }}
|
||||
onChange={onInputChange}
|
||||
/>
|
||||
</FormGroup>
|
||||
</ModalBody>
|
||||
|
||||
<ModalFooter className={styles.modalFooter}>
|
||||
<div className={styles.selected}>
|
||||
{translate('{count} import lists selected', { count: selectedCount })}
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<Button onPress={onModalClose}>{translate('Cancel')}</Button>
|
||||
|
||||
<Button onPress={save}>{translate('ApplyChanges')}</Button>
|
||||
</div>
|
||||
</ModalFooter>
|
||||
</ModalContent>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageImportListsEditModalContent;
|
||||
@@ -0,0 +1,20 @@
|
||||
import React from 'react';
|
||||
import Modal from 'Components/Modal/Modal';
|
||||
import ManageImportListsModalContent from './ManageImportListsModalContent';
|
||||
|
||||
interface ManageImportListsModalProps {
|
||||
isOpen: boolean;
|
||||
onModalClose(): void;
|
||||
}
|
||||
|
||||
function ManageImportListsModal(props: ManageImportListsModalProps) {
|
||||
const { isOpen, onModalClose } = props;
|
||||
|
||||
return (
|
||||
<Modal isOpen={isOpen} onModalClose={onModalClose}>
|
||||
<ManageImportListsModalContent onModalClose={onModalClose} />
|
||||
</Modal>
|
||||
);
|
||||
}
|
||||
|
||||
export default ManageImportListsModal;
|
||||
@@ -0,0 +1,16 @@
|
||||
.leftButtons,
|
||||
.rightButtons {
|
||||
display: flex;
|
||||
flex: 1 0 50%;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.rightButtons {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.deleteButton {
|
||||
composes: button from '~Components/Link/Button.css';
|
||||
|
||||
margin-right: 10px;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user