Compare commits

..

3 Commits

Author SHA1 Message Date
bakerboy448
e0b7a78568 CHANGELOG-v0.1.1.1320 2022-05-10 19:31:21 -05:00
bakerboy448
bc31f10770 changelog script workaround bad tags 2022-05-10 19:30:20 -05:00
bakerboy448
98ca518178 create changelog script 2022-05-10 19:29:58 -05:00
882 changed files with 7237 additions and 13251 deletions

View File

@@ -5,9 +5,9 @@ body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the bug you encountered. If a bug exists and is closed note that it may only be fixed in an unstable branch.
description: Please search to see if an issue already exists for the bug you encountered.
options:
- label: I have searched the existing open and closed issues
- label: I have searched the existing issues
required: true
- type: textarea
attributes:
@@ -42,14 +42,12 @@ body:
- **Docker Install**: Yes
- **Using Reverse Proxy**: No
- **Browser**: Firefox 90 (If UI related)
- **Database**: Sqlite 3.36.0
value: |
- OS:
- Readarr:
- Docker Install:
- Using Reverse Proxy:
- Browser:
- Database:
render: markdown
validations:
required: true

View File

@@ -5,9 +5,9 @@ body:
- type: checkboxes
attributes:
label: Is there an existing issue for this?
description: Please search to see if an open or closed issue already exists for the feature you are requesting. If a request exists and is closed note that it may only be fixed in an unstable branch.
description: Please search to see if an issue already exists for the feature you are requesting.
options:
- label: I have searched the existing open and closed issues
- label: I have searched the existing issues
required: true
- type: textarea
attributes:

View File

@@ -1,132 +0,0 @@
# Contributor Covenant Code of Conduct
## Our Pledge
We as members, contributors, and leaders pledge to make participation in our
community a harassment-free experience for everyone, regardless of age, body
size, visible or invisible disability, ethnicity, sex characteristics, gender
identity and expression, level of experience, education, socio-economic status,
nationality, personal appearance, race, caste, color, religion, or sexual
identity and orientation.
We pledge to act and interact in ways that contribute to an open, welcoming,
diverse, inclusive, and healthy community.
## Our Standards
Examples of behavior that contributes to a positive environment for our
community include:
* Demonstrating empathy and kindness toward other people
* Being respectful of differing opinions, viewpoints, and experiences
* Giving and gracefully accepting constructive feedback
* Accepting responsibility and apologizing to those affected by our mistakes,
and learning from the experience
* Focusing on what is best not just for us as individuals, but for the overall
community
Examples of unacceptable behavior include:
* The use of sexualized language or imagery, and sexual attention or advances of
any kind
* Trolling, insulting or derogatory comments, and personal or political attacks
* Public or private harassment
* Publishing others' private information, such as a physical or email address,
without their explicit permission
* Other conduct which could reasonably be considered inappropriate in a
professional setting
## Enforcement Responsibilities
Community leaders are responsible for clarifying and enforcing our standards of
acceptable behavior and will take appropriate and fair corrective action in
response to any behavior that they deem inappropriate, threatening, offensive,
or harmful.
Community leaders have the right and responsibility to remove, edit, or reject
comments, commits, code, wiki edits, issues, and other contributions that are
not aligned to this Code of Conduct, and will communicate reasons for moderation
decisions when appropriate.
## Scope
This Code of Conduct applies within all community spaces, and also applies when
an individual is officially representing the community in public spaces.
Examples of representing our community include using an official e-mail address,
posting via an official social media account, or acting as an appointed
representative at an online or offline event.
## Enforcement
Instances of abusive, harassing, or otherwise unacceptable behavior may be
reported to the community leaders responsible for enforcement at
<development@readarr.com>.
All complaints will be reviewed and investigated promptly and fairly.
All community leaders are obligated to respect the privacy and security of the
reporter of any incident.
## Enforcement Guidelines
Community leaders will follow these Community Impact Guidelines in determining
the consequences for any action they deem in violation of this Code of Conduct:
### 1. Correction
**Community Impact**: Use of inappropriate language or other behavior deemed
unprofessional or unwelcome in the community.
**Consequence**: A private, written warning from community leaders, providing
clarity around the nature of the violation and an explanation of why the
behavior was inappropriate. A public apology may be requested.
### 2. Warning
**Community Impact**: A violation through a single incident or series of
actions.
**Consequence**: A warning with consequences for continued behavior. No
interaction with the people involved, including unsolicited interaction with
those enforcing the Code of Conduct, for a specified period of time. This
includes avoiding interactions in community spaces as well as external channels
like social media. Violating these terms may lead to a temporary or permanent
ban.
### 3. Temporary Ban
**Community Impact**: A serious violation of community standards, including
sustained inappropriate behavior.
**Consequence**: A temporary ban from any sort of interaction or public
communication with the community for a specified period of time. No public or
private interaction with the people involved, including unsolicited interaction
with those enforcing the Code of Conduct, is allowed during this period.
Violating these terms may lead to a permanent ban.
### 4. Permanent Ban
**Community Impact**: Demonstrating a pattern of violation of community
standards, including sustained inappropriate behavior, harassment of an
individual, or aggression toward or disparagement of classes of individuals.
**Consequence**: A permanent ban from any sort of public interaction within the
community.
## Attribution
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
version 2.1, available at
[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1].
Community Impact Guidelines were inspired by
[Mozilla's code of conduct enforcement ladder][Mozilla CoC].
For answers to common questions about this code of conduct, see the FAQ at
[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at
[https://www.contributor-covenant.org/translations][translations].
[homepage]: https://www.contributor-covenant.org
[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html
[Mozilla CoC]: https://github.com/mozilla/diversity
[FAQ]: https://www.contributor-covenant.org/faq
[translations]: https://www.contributor-covenant.org/translations

View File

@@ -62,15 +62,6 @@ Support this project by becoming a sponsor. Your logo will show up here with a l
[![Mega Sponsors List](https://opencollective.com/Readarr/tiers/mega-sponsor.svg?width=890)](https://opencollective.com/readarr#mega-sponsor)
## DigitalOcean
This project is also supported by DigitalOcean
<p>
<a href="https://www.digitalocean.com/">
<img src="https://opensource.nyc3.cdn.digitaloceanspaces.com/attribution/assets/SVG/DO_Logo_horizontal_blue.svg" width="201px">
</a>
</p>
### License
* [GNU GPL v3](http://www.gnu.org/licenses/gpl.html)

View File

@@ -1,8 +0,0 @@
# Security Policy
## Reporting a Vulnerability
Please report (suspected) security vulnerabilities on Discord (preferred) to
any of the Servarr Dev role holders (red names) or via email: development@servarr.com. You will receive a response from
us within 72 hours. If the issue is confirmed, we will release a patch as soon
as possible depending on complexity/severity.

View File

@@ -9,13 +9,13 @@ variables:
testsFolder: './_tests'
yarnCacheFolder: $(Pipeline.Workspace)/.yarn
nugetCacheFolder: $(Pipeline.Workspace)/.nuget/packages
majorVersion: '0.1.2'
majorVersion: '0.1.1'
minorVersion: $[counter('minorVersion', 1)]
readarrVersion: '$(majorVersion).$(minorVersion)'
buildName: '$(Build.SourceBranchName).$(readarrVersion)'
sentryOrg: 'servarr'
sentryUrl: 'https://sentry.servarr.com'
dotnetVersion: '6.0.302'
dotnetVersion: '6.0.201'
innoVersion: '6.2.0'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
@@ -66,13 +66,16 @@ stages:
inputs:
version: $(dotnetVersion)
- bash: |
SDK_PATH="${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}"
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if ! grep -q freebsd-x64 $BUNDLEDVERSIONS; then
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props
echo $BUNDLEDVERSIONS
grep osx-x64 $BUNDLEDVERSIONS
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
echo "BSD already enabled"
else
echo "Enabling BSD support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' $BUNDLEDVERSIONS
fi
displayName: Extra Platform Support
displayName: Enable FreeBSD Support
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/src/Directory.Packages.props'
@@ -84,27 +87,29 @@ stages:
NUGET_PACKAGES: $(nugetCacheFolder)
- powershell: Get-ChildItem _output\net6.0*,_output\*.Update\* -Recurse | Where { $_.Fullname -notlike "*\publish\*" -and $_.attributes -notlike "*directory*" } | Remove-Item
displayName: Clean up intermediate output
- publish: $(outputFolder)
artifact: '$(osName)Backend'
- task: PublishPipelineArtifact@1
inputs:
path: $(outputFolder)
artifact: '$(osName)Backend'
artifactType: 'pipeline'
parallel: true
parallelCount: 100
displayName: Publish Backend
- publish: '$(testsFolder)/net6.0/win-x64/publish'
artifact: win-x64-tests
displayName: Publish win-x64 Test Package
artifact: WindowsCoreTests
displayName: Publish Windows Test Package
- publish: '$(testsFolder)/net6.0/linux-x64/publish'
artifact: linux-x64-tests
displayName: Publish linux-x64 Test Package
- publish: '$(testsFolder)/net6.0/linux-x86/publish'
artifact: linux-x86-tests
displayName: Publish linux-x86 Test Package
artifact: LinuxCoreTests
displayName: Publish Linux Test Package
- publish: '$(testsFolder)/net6.0/linux-musl-x64/publish'
artifact: linux-musl-x64-tests
displayName: Publish linux-musl-x64 Test Package
artifact: LinuxMuslCoreTests
displayName: Publish Linux Musl Test Package
- publish: '$(testsFolder)/net6.0/freebsd-x64/publish'
artifact: freebsd-x64-tests
displayName: Publish freebsd-x64 Test Package
artifact: FreebsdCoreTests
displayName: Publish FreeBSD Test Package
- publish: '$(testsFolder)/net6.0/osx-x64/publish'
artifact: osx-x64-tests
displayName: Publish osx-x64 Test Package
artifact: MacCoreTests
displayName: Publish MacOS Test Package
- stage: Build_Backend_Other
displayName: Build Backend (Other OS)
@@ -136,29 +141,25 @@ stages:
inputs:
version: $(dotnetVersion)
- bash: |
SDK_PATH="${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}"
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if ! grep -q freebsd-x64 $BUNDLEDVERSIONS; then
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
BUNDLEDVERSIONS=${AGENT_TOOLSDIRECTORY}/dotnet/sdk/${DOTNETVERSION}/Microsoft.NETCoreSdk.BundledVersions.props
echo $BUNDLEDVERSIONS
grep osx-x64 $BUNDLEDVERSIONS
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
echo "BSD already enabled"
else
echo "Enabling BSD support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64/' $BUNDLEDVERSIONS
fi
displayName: Extra Platform Support
displayName: Enable FreeBSD Support
- task: Cache@2
inputs:
key: 'nuget | "$(Agent.OS)" | $(Build.SourcesDirectory)/src/Directory.Packages.props'
path: $(nugetCacheFolder)
displayName: Cache NuGet packages
- bash: ./build.sh --backend --enable-extra-platforms
- bash: ./build.sh --backend --enable-bsd
displayName: Build Readarr Backend
env:
NUGET_PACKAGES: $(nugetCacheFolder)
- bash: |
find ${OUTPUTFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
find ${OUTPUTFOLDER} -depth -empty -type d -exec rm -r "{}" \;
find ${TESTSFOLDER} -type f ! -path "*/publish/*" -exec rm -rf {} \;
find ${TESTSFOLDER} -depth -empty -type d -exec rm -r "{}" \;
displayName: Clean up intermediate output
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
- stage: Build_Frontend
displayName: Frontend
@@ -261,35 +262,35 @@ stages:
artifactName: WindowsFrontend
targetPath: _output
displayName: Fetch Frontend
- bash: ./build.sh --packages --enable-extra-platforms
- bash: ./build.sh --packages --enable-bsd
displayName: Create Packages
- bash: |
find . -name "Readarr" -exec chmod a+x {} \;
find . -name "Readarr.Update" -exec chmod a+x {} \;
displayName: Set executable bits
- task: ArchiveFiles@2
displayName: Create win-x64 zip
displayName: Create Windows Core zip
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).windows-core-x64.zip'
archiveType: 'zip'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/win-x64/net6.0
- task: ArchiveFiles@2
displayName: Create win-x86 zip
displayName: Create Windows x86 Core zip
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).windows-core-x86.zip'
archiveType: 'zip'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/win-x86/net6.0
- task: ArchiveFiles@2
displayName: Create osx-x64 app
displayName: Create MacOS x64 Core app
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).osx-app-core-x64.zip'
archiveType: 'zip'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-x64-app/net6.0
- task: ArchiveFiles@2
displayName: Create osx-x64 tar
displayName: Create MacOS x64 Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).osx-core-x64.tar.gz'
archiveType: 'tar'
@@ -297,14 +298,14 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-x64/net6.0
- task: ArchiveFiles@2
displayName: Create osx-arm64 app
displayName: Create MacOS arm64 Core app
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).osx-app-core-arm64.zip'
archiveType: 'zip'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-arm64-app/net6.0
- task: ArchiveFiles@2
displayName: Create osx-arm64 tar
displayName: Create MacOS arm64 Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).osx-core-arm64.tar.gz'
archiveType: 'tar'
@@ -312,7 +313,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/osx-arm64/net6.0
- task: ArchiveFiles@2
displayName: Create linux-x64 tar
displayName: Create Linux Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-core-x64.tar.gz'
archiveType: 'tar'
@@ -320,7 +321,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-x64/net6.0
- task: ArchiveFiles@2
displayName: Create linux-musl-x64 tar
displayName: Create Linux Musl Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-musl-core-x64.tar.gz'
archiveType: 'tar'
@@ -328,15 +329,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-x64/net6.0
- task: ArchiveFiles@2
displayName: Create linux-x86 tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-core-x86.tar.gz'
archiveType: 'tar'
tarCompression: 'gz'
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-x86/net6.0
- task: ArchiveFiles@2
displayName: Create linux-arm tar
displayName: Create ARM32 Linux Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-core-arm.tar.gz'
archiveType: 'tar'
@@ -344,7 +337,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-arm/net6.0
- task: ArchiveFiles@2
displayName: Create linux-musl-arm tar
displayName: Create ARM32 Linux Musl Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-musl-core-arm.tar.gz'
archiveType: 'tar'
@@ -352,7 +345,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm/net6.0
- task: ArchiveFiles@2
displayName: Create linux-arm64 tar
displayName: Create Linux arm64 Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-core-arm64.tar.gz'
archiveType: 'tar'
@@ -360,7 +353,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-arm64/net6.0
- task: ArchiveFiles@2
displayName: Create linux-musl-arm64 tar
displayName: Create ARM64 Linux Musl Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).linux-musl-core-arm64.tar.gz'
archiveType: 'tar'
@@ -368,7 +361,7 @@ stages:
includeRootFolder: false
rootFolderOrFile: $(artifactsFolder)/linux-musl-arm64/net6.0
- task: ArchiveFiles@2
displayName: Create freebsd-x64 tar
displayName: Create FreeBSD Core Core tar
inputs:
archiveFile: '$(Build.ArtifactStagingDirectory)/Readarr.$(buildName).freebsd-core-x64.tar.gz'
archiveType: 'tar'
@@ -420,22 +413,22 @@ stages:
matrix:
MacCore:
osName: 'Mac'
testName: 'osx-x64'
testName: 'MacCore'
poolName: 'Azure Pipelines'
imageName: ${{ variables.macImage }}
WindowsCore:
osName: 'Windows'
testName: 'win-x64'
testName: 'WindowsCore'
poolName: 'Azure Pipelines'
imageName: ${{ variables.windowsImage }}
LinuxCore:
osName: 'Linux'
testName: 'linux-x64'
testName: 'LinuxCore'
poolName: 'Azure Pipelines'
imageName: ${{ variables.linuxImage }}
FreebsdCore:
osName: 'Linux'
testName: 'freebsd-x64'
testName: 'FreebsdCore'
poolName: 'FreeBSD'
imageName:
@@ -454,7 +447,7 @@ stages:
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: '$(testName)-tests'
artifactName: '$(testName)Tests'
targetPath: $(testsFolder)
- powershell: Set-Service SCardSvr -StartupType Manual
displayName: Enable Windows Test Service
@@ -482,12 +475,8 @@ stages:
matrix:
alpine:
testName: 'Musl Net Core'
artifactName: linux-musl-x64-tests
artifactName: LinuxMuslCoreTests
containerImage: ghcr.io/servarr/testimages:alpine
linux-x86:
testName: 'linux-x86'
artifactName: linux-x86-tests
containerImage: ghcr.io/servarr/testimages:linux-x86
pool:
vmImage: ${{ variables.linuxImage }}
@@ -498,15 +487,9 @@ stages:
steps:
- task: UseDotNet@2
displayName: 'Install .NET'
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
condition: and(succeeded(), ne(variables['testName'], 'linux-x86'))
- bash: |
SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$)
curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet
displayName: 'Install .NET'
condition: and(succeeded(), eq(variables['testName'], 'linux-x86'))
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
@@ -529,57 +512,6 @@ stages:
testResultsFiles: '**/TestResult.xml'
testRunTitle: '$(testName) Unit Tests'
failTaskOnFailedTests: true
- job: Unit_LinuxCore_Postgres
displayName: Unit Native LinuxCore with Postgres Database
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
artifactName: LinuxCoreTests
Readarr__Postgres__Host: 'localhost'
Readarr__Postgres__Port: '5432'
Readarr__Postgres__User: 'readarr'
Readarr__Postgres__Password: 'readarr'
pool:
vmImage: ${{ variables.linuxImage }}
timeoutInMinutes: 10
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: 'linux-x64-Tests'
targetPath: $(testsFolder)
- bash: find ${TESTSFOLDER} -name "Readarr.Test.Dummy" -exec chmod a+x {} \;
displayName: Make Test Dummy Executable
condition: and(succeeded(), ne(variables['osName'], 'Windows'))
- bash: |
docker run -d --name=postgres14 \
-e POSTGRES_PASSWORD=readarr \
-e POSTGRES_USER=readarr \
-p 5432:5432/tcp \
-v /usr/share/zoneinfo/America/Chicago:/etc/localtime:ro \
postgres:14
displayName: Start postgres
- bash: |
chmod a+x ${TESTSFOLDER}/test.sh
ls -lR ${TESTSFOLDER}
${TESTSFOLDER}/test.sh Linux Unit Test
displayName: Run Tests
- task: PublishTestResults@2
displayName: Publish Test Results
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'LinuxCore Postgres Unit Tests'
failTaskOnFailedTests: true
- stage: Integration
displayName: Integration
@@ -591,17 +523,17 @@ stages:
matrix:
MacCore:
osName: 'Mac'
testName: 'osx-x64'
testName: 'MacCore'
imageName: ${{ variables.macImage }}
pattern: 'Readarr.*.osx-core-x64.tar.gz'
WindowsCore:
osName: 'Windows'
testName: 'win-x64'
testName: 'WindowsCore'
imageName: ${{ variables.windowsImage }}
pattern: 'Readarr.*.windows-core-x64.zip'
LinuxCore:
osName: 'Linux'
testName: 'linux-x64'
testName: 'LinuxCore'
imageName: ${{ variables.linuxImage }}
pattern: 'Readarr.*.linux-core-x64.tar.gz'
@@ -618,7 +550,7 @@ stages:
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: '$(testName)-tests'
artifactName: '$(testName)Tests'
targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2
displayName: Download Build Artifact
@@ -648,66 +580,6 @@ stages:
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Integration_LinuxCore_Postgres
displayName: Integration Native LinuxCore with Postgres Database
variables:
pattern: 'Readarr.*.linux-core-x64.tar.gz'
Readarr__Postgres__Host: 'localhost'
Readarr__Postgres__Port: '5432'
Readarr__Postgres__User: 'readarr'
Readarr__Postgres__Password: 'readarr'
pool:
vmImage: ${{ variables.linuxImage }}
steps:
- task: UseDotNet@2
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: 'linux-x64-tests'
targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2
displayName: Download Build Artifact
inputs:
buildType: 'current'
artifactName: Packages
itemPattern: '**/$(pattern)'
targetPath: $(Build.ArtifactStagingDirectory)
- task: ExtractFiles@1
inputs:
archiveFilePatterns: '$(Build.ArtifactStagingDirectory)/**/$(pattern)'
destinationFolder: '$(Build.ArtifactStagingDirectory)/bin'
displayName: Extract Package
- bash: |
mkdir -p ./bin/
cp -r -v ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin/Readarr/. ./bin/
displayName: Move Package Contents
- bash: |
docker run -d --name=postgres14 \
-e POSTGRES_PASSWORD=readarr \
-e POSTGRES_USER=readarr \
-p 5432:5432/tcp \
-v /usr/share/zoneinfo/America/Chicago:/etc/localtime:ro \
postgres:14
displayName: Start postgres
- bash: |
chmod a+x ${TESTSFOLDER}/test.sh
${TESTSFOLDER}/test.sh Linux Integration Test
displayName: Run Integration Tests
- task: PublishTestResults@2
inputs:
testResultsFormat: 'NUnit'
testResultsFiles: '**/TestResult.xml'
testRunTitle: 'Integration LinuxCore Postgres Database Integration Tests'
failTaskOnFailedTests: true
displayName: Publish Test Results
- job: Integration_FreeBSD
displayName: Integration Native FreeBSD
workspace:
@@ -723,14 +595,14 @@ stages:
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: 'freebsd-x64-tests'
artifactName: 'FreebsdCoreTests'
targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2
displayName: Download Build Artifact
inputs:
buildType: 'current'
artifactName: Packages
itemPattern: '**/$(pattern)'
itemPattern: '/$(pattern)'
targetPath: $(Build.ArtifactStagingDirectory)
- bash: |
mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
@@ -757,15 +629,11 @@ stages:
strategy:
matrix:
alpine:
testName: 'linux-musl-x64'
artifactName: linux-musl-x64-tests
testName: 'Musl Net Core'
artifactName: LinuxMuslCoreTests
containerImage: ghcr.io/servarr/testimages:alpine
pattern: 'Readarr.*.linux-musl-core-x64.tar.gz'
linux-x86:
testName: 'linux-x86'
artifactName: linux-x86-tests
containerImage: ghcr.io/servarr/testimages:linux-x86
pattern: 'Readarr.*.linux-core-x86.tar.gz'
pool:
vmImage: ${{ variables.linuxImage }}
@@ -775,15 +643,9 @@ stages:
steps:
- task: UseDotNet@2
displayName: 'Install .NET'
displayName: 'Install .net core'
inputs:
version: $(dotnetVersion)
condition: and(succeeded(), ne(variables['testName'], 'linux-x86'))
- bash: |
SDKURL=$(curl -s https://api.github.com/repos/Servarr/dotnet-linux-x86/releases | jq -rc '.[].assets[].browser_download_url' | grep sdk-${DOTNETVERSION}.*gz$)
curl -fsSL $SDKURL | tar xzf - -C /opt/dotnet
displayName: 'Install .NET'
condition: and(succeeded(), eq(variables['testName'], 'linux-x86'))
- checkout: none
- task: DownloadPipelineArtifact@2
displayName: Download Test Artifact
@@ -829,17 +691,14 @@ stages:
matrix:
Linux:
osName: 'Linux'
artifactName: 'linux-x64'
imageName: ${{ variables.linuxImage }}
pattern: 'Readarr.*.linux-core-x64.tar.gz'
Mac:
osName: 'Mac'
artifactName: 'osx-x64'
imageName: ${{ variables.macImage }}
pattern: 'Readarr.*.osx-core-x64.tar.gz'
Windows:
osName: 'Windows'
artifactName: 'win-x64'
imageName: ${{ variables.windowsImage }}
pattern: 'Readarr.*.windows-core-x64.zip'
@@ -856,7 +715,7 @@ stages:
displayName: Download Test Artifact
inputs:
buildType: 'current'
artifactName: '$(artifactName)-tests'
artifactName: '$(osName)CoreTests'
targetPath: $(testsFolder)
- task: DownloadPipelineArtifact@2
displayName: Download Build Artifact
@@ -1050,4 +909,3 @@ stages:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
DISCORDCHANNELID: $(discordChannelId)
DISCORDWEBHOOKKEY: $(discordWebhookKey)
DISCORDTHREADID: $(discordThreadId)

View File

@@ -27,22 +27,15 @@ UpdateVersionNumber()
fi
}
EnableExtraPlatformsInSDK()
EnableBsdSupport()
{
SDK_PATH=$(dotnet --list-sdks | grep -P '6\.\d\.\d+' | head -1 | sed 's/\(6\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
BUNDLEDVERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
if grep -q freebsd-x64 $BUNDLEDVERSIONS; then
echo "Extra platforms already enabled"
else
echo "Enabling extra platform support"
sed -i.ORI 's/osx-x64/osx-x64;freebsd-x64;linux-x86/' $BUNDLEDVERSIONS
fi
}
#todo enable sdk with
#SDK_PATH=$(dotnet --list-sdks | grep -P '5\.\d\.\d+' | head -1 | sed 's/\(5\.[0-9]*\.[0-9]*\).*\[\(.*\)\]/\2\/\1/g')
# BUNDLED_VERSIONS="${SDK_PATH}/Microsoft.NETCoreSdk.BundledVersions.props"
EnableExtraPlatforms()
{
if grep -qv freebsd-x64 src/Directory.Build.props; then
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64;linux-x86</RuntimeIdentifiers>^g" src/Directory.Build.props
sed -i'' -e "s^<RuntimeIdentifiers>\(.*\)</RuntimeIdentifiers>^<RuntimeIdentifiers>\1;freebsd-x64</RuntimeIdentifiers>^g" src/Directory.Build.props
sed -i'' -e "s^<ExcludedRuntimeFrameworkPairs>\(.*\)</ExcludedRuntimeFrameworkPairs>^<ExcludedRuntimeFrameworkPairs>\1;freebsd-x64:net472</ExcludedRuntimeFrameworkPairs>^g" src/Directory.Build.props
fi
}
@@ -299,8 +292,7 @@ if [ $# -eq 0 ]; then
PACKAGES=YES
INSTALLER=NO
LINT=YES
ENABLE_EXTRA_PLATFORMS=NO
ENABLE_EXTRA_PLATFORMS_IN_SDK=NO
ENABLE_BSD=NO
fi
while [[ $# -gt 0 ]]
@@ -312,12 +304,8 @@ case $key in
BACKEND=YES
shift # past argument
;;
--enable-bsd|--enable-extra-platforms)
ENABLE_EXTRA_PLATFORMS=YES
shift # past argument
;;
--enable-extra-platforms-in-sdk)
ENABLE_EXTRA_PLATFORMS_IN_SDK=YES
--enable-bsd)
ENABLE_BSD=YES
shift # past argument
;;
-r|--runtime)
@@ -361,17 +349,12 @@ esac
done
set -- "${POSITIONAL[@]}" # restore positional parameters
if [ "$ENABLE_EXTRA_PLATFORMS_IN_SDK" = "YES" ];
then
EnableExtraPlatformsInSDK
fi
if [ "$BACKEND" = "YES" ];
then
UpdateVersionNumber
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
if [ "$ENABLE_BSD" = "YES" ];
then
EnableExtraPlatforms
EnableBsdSupport
fi
Build
if [[ -z "$RID" || -z "$FRAMEWORK" ]];
@@ -381,10 +364,9 @@ then
PackageTests "net6.0" "linux-x64"
PackageTests "net6.0" "linux-musl-x64"
PackageTests "net6.0" "osx-x64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
if [ "$ENABLE_BSD" = "YES" ];
then
PackageTests "net6.0" "freebsd-x64"
PackageTests "net6.0" "linux-x86"
fi
else
PackageTests "$FRAMEWORK" "$RID"
@@ -423,10 +405,9 @@ then
Package "net6.0" "linux-musl-arm"
Package "net6.0" "osx-x64"
Package "net6.0" "osx-arm64"
if [ "$ENABLE_EXTRA_PLATFORMS" = "YES" ];
if [ "$ENABLE_BSD" = "YES" ];
then
Package "net6.0" "freebsd-x64"
Package "net6.0" "linux-x86"
fi
else
Package "$FRAMEWORK" "$RID"

View File

@@ -0,0 +1,94 @@
# New Beta Release
Readarr v0.1.1.1320 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.
- **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
- Automated API Documentation Updates recently implemented
- [Wiki Contributions](https://wiki.servarr.com/readarr) and updates welcome and encouraged on the Wiki itself or via GitHub
# Additional Commentary
- [Lidarr v1 released](https://www.reddit.com/r/Lidarr/comments/ul0b2w/new_release_develop_v1012578/)
- [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
- Radarr Postgres Database Support in `nightly` and `develop`
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)
# Releases
## Native
- [GitHub Releases](https://github.com/Readarr/Readarr/releases)
- [Wiki Installation Instructions](https://wiki.servarr.com/readarr/installation)
## Docker
- [hotio/Readarr:testing](https://hotio.dev/containers/readarr)
- [lscr.io/linuxserver/Readarr:develop](https://docs.linuxserver.io/images/docker-readarr)
## 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
## v0.1.1.1320 (changes since v0.1.0.1248)
- Fixed: Correct User-Agent api logging
- Fixed: UI hiding search results with duplicate GUIDs
- New: Add date picker for custom filter dates
- Fixed: Interactive Search Filter not filtering multiple qualities in the same filter row
- Fixed: Clarify Qbit Content Path Error
- Fixed: Properly handle 119 error code from Synology Download Station
- Fixed: API error when sending payload without optional parameters
- Fixed: Cleanup Temp files after backup creation
- Fixed: Loading old commands from database
- New: Update Cert Validation Help Text
- Fixed: Clarify Indexer Priority Helptext
- Fixed: Improve help text for download client Category
- Fixed: IPv4 instead of IP4
- New: Add Validations for Recycle Bin Folder
- New: .NET 6.0.3
- Fixed: Healthcheck warning message used incorrect variable
- Fixed: Assume SABnzbd develop version is 3.0.0 if not specified
- Fixed: Updater version number logging
- Fixed: Update from version in logs
- New: Add more information about Windows service to installer
- Fixed: Recycle bin log message
- Fixed: Make authentication cookie name unique to Readarr
- Other bug fixes and improvements, see GitHub history

View File

@@ -0,0 +1,2 @@
- Automated API Documentation Updates recently implemented
- [Wiki Contributions](https://wiki.servarr.com/readarr) and updates welcome and encouraged on the Wiki itself or via GitHub

View File

@@ -0,0 +1,6 @@
- **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.
- **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.

View File

@@ -0,0 +1,6 @@
- **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.**
- **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.**

View File

@@ -0,0 +1,4 @@
- [Lidarr v1 released](https://www.reddit.com/r/Lidarr/comments/ul0b2w/new_release_develop_v1012578/)
- [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
- Radarr Postgres Database Support in `nightly` and `develop`
- [Lidarr Postgres Database Support in development (Draft PR#2625)](https://github.com/Lidarr/Lidarr/pull/2625)

View File

@@ -39,7 +39,6 @@ module.exports = {
plugins: [
'filenames',
'react',
'react-hooks',
'simple-import-sort',
'import'
],
@@ -309,9 +308,7 @@ module.exports = {
'react/react-in-jsx-scope': 2,
'react/self-closing-comp': 2,
'react/sort-comp': 2,
'react/jsx-wrap-multilines': 2,
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'error'
'react/jsx-wrap-multilines': 2
},
overrides: [
{

View File

@@ -1,6 +1,7 @@
const reload = require('require-nocache')(module);
const cssVarsFiles = [
'./src/Styles/Variables/colors',
'./src/Styles/Variables/dimensions',
'./src/Styles/Variables/fonts',
'./src/Styles/Variables/animations',

View File

@@ -61,33 +61,33 @@ class Blocklist extends Component {
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
};
}
//
// Listeners
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
};
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
};
}
onRemoveSelectedPress = () => {
this.setState({ isConfirmRemoveModalOpen: true });
};
}
onRemoveSelectedConfirmed = () => {
this.props.onRemoveSelected(this.getSelectedIds());
this.setState({ isConfirmRemoveModalOpen: false });
};
}
onConfirmRemoveModalClose = () => {
this.setState({ isConfirmRemoveModalOpen: false });
};
}
//
// Render

View File

@@ -68,37 +68,37 @@ class BlocklistConnector extends Component {
repopulate = () => {
this.props.fetchBlocklist();
};
}
//
// Listeners
onFirstPagePress = () => {
this.props.gotoBlocklistFirstPage();
};
}
onPreviousPagePress = () => {
this.props.gotoBlocklistPreviousPage();
};
}
onNextPagePress = () => {
this.props.gotoBlocklistNextPage();
};
}
onLastPagePress = () => {
this.props.gotoBlocklistLastPage();
};
}
onPageSelect = (page) => {
this.props.gotoBlocklistPage({ page });
};
}
onRemoveSelected = (ids) => {
this.props.removeBlocklistItems({ ids });
};
}
onSortPress = (sortKey) => {
this.props.setBlocklistSort({ sortKey });
};
}
onTableOptionChange = (payload) => {
this.props.setBlocklistTableOption(payload);
@@ -106,11 +106,11 @@ class BlocklistConnector extends Component {
if (payload.pageSize) {
this.props.gotoBlocklistFirstPage();
}
};
}
onClearBlocklistPress = () => {
this.props.executeCommand({ name: commandNames.CLEAR_BLOCKLIST });
};
}
//
// Render

View File

@@ -30,11 +30,11 @@ class BlocklistRow extends Component {
onDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
//
// Render

View File

@@ -60,38 +60,38 @@ class HistoryConnector extends Component {
repopulate = () => {
this.props.fetchHistory();
};
}
//
// Listeners
onFirstPagePress = () => {
this.props.gotoHistoryFirstPage();
};
}
onPreviousPagePress = () => {
this.props.gotoHistoryPreviousPage();
};
}
onNextPagePress = () => {
this.props.gotoHistoryNextPage();
};
}
onLastPagePress = () => {
this.props.gotoHistoryLastPage();
};
}
onPageSelect = (page) => {
this.props.gotoHistoryPage({ page });
};
}
onSortPress = (sortKey) => {
this.props.setHistorySort({ sortKey });
};
}
onFilterSelect = (selectedFilterKey) => {
this.props.setHistoryFilter({ selectedFilterKey });
};
}
onTableOptionChange = (payload) => {
this.props.setHistoryTableOption(payload);
@@ -99,7 +99,7 @@ class HistoryConnector extends Component {
if (payload.pageSize) {
this.props.gotoHistoryFirstPage();
}
};
}
//
// Render

View File

@@ -40,11 +40,11 @@ class HistoryRow extends Component {
onDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
//
// Render
@@ -169,16 +169,6 @@ class HistoryRow extends Component {
);
}
if (name === 'sourceTitle') {
return (
<TableRowCell
key={name}
>
{sourceTitle}
</TableRowCell>
);
}
if (name === 'details') {
return (
<TableRowCell

View File

@@ -49,7 +49,7 @@ class HistoryRowConnector extends Component {
onMarkAsFailedPress = () => {
this.props.markAsFailed({ id: this.props.id });
};
}
//
// Render

View File

@@ -1,13 +1,13 @@
.torrent {
composes: label from '~Components/Label.css';
border-color: var(--torrentColor);
background-color: var(--torrentColor);
border-color: $torrentColor;
background-color: $torrentColor;
}
.usenet {
composes: label from '~Components/Label.css';
border-color: var(--usenetColor);
background-color: var(--usenetColor);
border-color: $usenetColor;
background-color: $usenetColor;
}

View File

@@ -75,23 +75,13 @@ class Queue extends Component {
return;
}
const nextState = {};
if (prevProps.items !== items) {
nextState.items = items;
}
const selectedIds = this.getSelectedIds();
const isPendingSelected = _.some(this.props.items, (item) => {
return selectedIds.indexOf(item.id) > -1 && item.status === 'delay';
});
if (isPendingSelected !== this.state.isPendingSelected) {
nextState.isPendingSelected = isPendingSelected;
}
if (!_.isEmpty(nextState)) {
this.setState(nextState);
this.setState({ isPendingSelected });
}
}
@@ -100,45 +90,45 @@ class Queue extends Component {
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
};
}
//
// Listeners
onQueueRowModalOpenOrClose = (isOpen) => {
this._shouldBlockRefresh = isOpen;
};
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
};
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
};
}
onGrabSelectedPress = () => {
this.props.onGrabSelectedPress(this.getSelectedIds());
};
}
onRemoveSelectedPress = () => {
this.setState({ isConfirmRemoveModalOpen: true }, () => {
this._shouldBlockRefresh = true;
});
};
}
onRemoveSelectedConfirmed = (payload) => {
this._shouldBlockRefresh = false;
this.props.onRemoveSelectedPress({ ids: this.getSelectedIds(), ...payload });
this.setState({ isConfirmRemoveModalOpen: false });
};
}
onConfirmRemoveModalClose = () => {
this._shouldBlockRefresh = false;
this.setState({ isConfirmRemoveModalOpen: false });
};
}
//
// Render
@@ -226,29 +216,26 @@ class Queue extends Component {
<PageContentBody>
{
isRefreshing && !isAllPopulated ?
<LoadingIndicator /> :
null
isRefreshing && !isAllPopulated &&
<LoadingIndicator />
}
{
!isRefreshing && hasError ?
!isRefreshing && hasError &&
<div>
{translate('FailedToLoadQueue')}
</div> :
null
</div>
}
{
isAllPopulated && !hasError && !items.length ?
isAllPopulated && !hasError && !items.length &&
<div>
{translate('QueueIsEmpty')}
</div> :
null
</div>
}
{
isAllPopulated && !hasError && !!items.length ?
isAllPopulated && !hasError && !!items.length &&
<div>
<Table
columns={columns}
@@ -283,8 +270,7 @@ class Queue extends Component {
isFetching={isRefreshing}
{...otherProps}
/>
</div> :
null
</div>
}
</PageContentBody>

View File

@@ -79,34 +79,34 @@ class QueueConnector extends Component {
repopulate = () => {
this.props.fetchQueue();
};
}
//
// Listeners
onFirstPagePress = () => {
this.props.gotoQueueFirstPage();
};
}
onPreviousPagePress = () => {
this.props.gotoQueuePreviousPage();
};
}
onNextPagePress = () => {
this.props.gotoQueueNextPage();
};
}
onLastPagePress = () => {
this.props.gotoQueueLastPage();
};
}
onPageSelect = (page) => {
this.props.gotoQueuePage({ page });
};
}
onSortPress = (sortKey) => {
this.props.setQueueSort({ sortKey });
};
}
onTableOptionChange = (payload) => {
this.props.setQueueTableOption(payload);
@@ -114,21 +114,21 @@ class QueueConnector extends Component {
if (payload.pageSize) {
this.props.gotoQueueFirstPage();
}
};
}
onRefreshPress = () => {
this.props.executeCommand({
name: commandNames.REFRESH_MONITORED_DOWNLOADS
});
};
}
onGrabSelectedPress = (ids) => {
this.props.grabQueueItems({ ids });
};
}
onRemoveSelectedPress = (payload) => {
this.props.removeQueueItems(payload);
};
}
//
// Render

View File

@@ -42,7 +42,7 @@ class QueueOptions extends Component {
[name]: value
});
});
};
}
//
// Render

View File

@@ -41,7 +41,7 @@ class QueueRow extends Component {
onRemoveQueueItemPress = () => {
this.setState({ isRemoveQueueItemModalOpen: true });
};
}
onRemoveQueueItemModalConfirmed = (blocklist, skipredownload) => {
const {
@@ -53,25 +53,25 @@ class QueueRow extends Component {
onRemoveQueueItemPress(blocklist, skipredownload);
this.setState({ isRemoveQueueItemModalOpen: false });
};
}
onRemoveQueueItemModalClose = () => {
this.props.onQueueRowModalOpenOrClose(false);
this.setState({ isRemoveQueueItemModalOpen: false });
};
}
onInteractiveImportPress = () => {
this.props.onQueueRowModalOpenOrClose(true);
this.setState({ isInteractiveImportModalOpen: true });
};
}
onInteractiveImportModalClose = () => {
this.props.onQueueRowModalOpenOrClose(false);
this.setState({ isInteractiveImportModalOpen: false });
};
}
//
// Render

View File

@@ -41,11 +41,11 @@ class QueueRowConnector extends Component {
onGrabPress = () => {
this.props.grabQueueItem({ id: this.props.id });
};
}
onRemoveQueueItemPress = (payload) => {
this.props.removeQueueItem({ id: this.props.id, ...payload });
};
}
//
// Render

View File

@@ -36,34 +36,34 @@ class RemoveQueueItemModal extends Component {
blocklist: false,
skipredownload: false
});
};
}
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
}
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
}
onSkipReDownloadChange = ({ value }) => {
this.setState({ skipredownload: value });
};
}
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
}
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
}
//
// Render

View File

@@ -31,40 +31,40 @@ class RemoveQueueItemsModal extends Component {
//
// Control
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipredownload: false
});
};
resetState = function() {
this.setState({
remove: true,
blocklist: false,
skipredownload: false
});
}
//
// Listeners
//
// Listeners
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
};
onRemoveChange = ({ value }) => {
this.setState({ remove: value });
}
onBlocklistChange = ({ value }) => {
this.setState({ blocklist: value });
};
}
onSkipReDownloadChange = ({ value }) => {
this.setState({ skipredownload: value });
};
}
onRemoveConfirmed = () => {
const state = this.state;
this.resetState();
this.props.onRemovePress(state);
};
}
onModalClose = () => {
this.resetState();
this.props.onModalClose();
};
}
//
// Render

View File

@@ -8,17 +8,17 @@ function AuthorMonitorNewItemsOptionsPopoverContent() {
<DescriptionList>
<DescriptionListItem
title={translate('AllBooks')}
data={translate('DataNewAllBooks')}
data="Monitor all new books"
/>
<DescriptionListItem
title={translate('NewBooks')}
data={translate('DataNewBooks')}
data="Monitor new books released after the newest existing book"
/>
<DescriptionListItem
title={translate('None')}
data={translate('DataNewNone')}
data="Don't monitor any new books"
/>
</DescriptionList>
);

View File

@@ -8,42 +8,42 @@ function AuthorMonitoringOptionsPopoverContent() {
return (
<>
<Alert>
{translate('MonitoringOptionsHelpText')}
This is a one time adjustment to set which books are monitored
</Alert>
<DescriptionList>
<DescriptionListItem
title={translate('AllBooks')}
data={translate('DataAllBooks')}
data="Monitor all books"
/>
<DescriptionListItem
title={translate('FutureBooks')}
data={translate('DataFutureBooks')}
data="Monitor books that have not released yet"
/>
<DescriptionListItem
title={translate('MissingBooks')}
data={translate('DataMissingBooks')}
data="Monitor books that do not have files or have not released yet"
/>
<DescriptionListItem
title={translate('ExistingBooks')}
data={translate('DataExistingBooks')}
data="Monitor books that have files or have not released yet"
/>
<DescriptionListItem
title={translate('FirstBook')}
data={translate('DataFirstBook')}
data="Monitor the first book. All other books will be ignored"
/>
<DescriptionListItem
title={translate('LatestBook')}
data={translate('DataLatestBook')}
data="Monitor the latest book and future books"
/>
<DescriptionListItem
title={translate('None')}
data={translate('DataNone')}
data="No books will be monitored"
/>
</DescriptionList>
</>

View File

@@ -4,19 +4,16 @@ import React from 'react';
import DocumentTitle from 'react-document-title';
import { Provider } from 'react-redux';
import PageConnector from 'Components/Page/PageConnector';
import ApplyTheme from './ApplyTheme';
import AppRoutes from './AppRoutes';
function App({ store, history }) {
return (
<DocumentTitle title={window.Readarr.instanceName}>
<DocumentTitle title="Readarr">
<Provider store={store}>
<ConnectedRouter history={history}>
<ApplyTheme>
<PageConnector>
<AppRoutes app={App} />
</PageConnector>
</ApplyTheme>
<PageConnector>
<AppRoutes app={App} />
</PageConnector>
</ConnectedRouter>
</Provider>
</DocumentTitle>

View File

@@ -22,7 +22,7 @@ import MediaManagementConnector from 'Settings/MediaManagement/MediaManagementCo
import MetadataSettings from 'Settings/Metadata/MetadataSettings';
import NotificationSettings from 'Settings/Notifications/NotificationSettings';
import Profiles from 'Settings/Profiles/Profiles';
import QualityConnector from 'Settings/Quality/QualityConnector';
import Quality from 'Settings/Quality/Quality';
import Settings from 'Settings/Settings';
import TagSettings from 'Settings/Tags/TagSettings';
import UISettingsConnector from 'Settings/UI/UISettingsConnector';
@@ -172,7 +172,7 @@ function AppRoutes(props) {
<Route
path="/settings/quality"
component={QualityConnector}
component={Quality}
/>
<Route

View File

@@ -11,47 +11,9 @@ import UpdateChanges from 'System/Updates/UpdateChanges';
import translate from 'Utilities/String/translate';
import styles from './AppUpdatedModalContent.css';
function mergeUpdates(items, version, prevVersion) {
let installedIndex = items.findIndex((u) => u.version === version);
let installedPreviouslyIndex = items.findIndex((u) => u.version === prevVersion);
if (installedIndex === -1) {
installedIndex = 0;
}
if (installedPreviouslyIndex === -1) {
installedPreviouslyIndex = items.length;
} else if (installedPreviouslyIndex === installedIndex && items.length) {
installedPreviouslyIndex += 1;
}
const appliedUpdates = items.slice(installedIndex, installedPreviouslyIndex);
if (!appliedUpdates.length) {
return null;
}
const appliedChanges = { new: [], fixed: [] };
appliedUpdates.forEach((u) => {
if (u.changes) {
appliedChanges.new.push(... u.changes.new);
appliedChanges.fixed.push(... u.changes.fixed);
}
});
const mergedUpdate = Object.assign({}, appliedUpdates[0], { changes: appliedChanges });
if (!appliedChanges.new.length && !appliedChanges.fixed.length) {
mergedUpdate.changes = null;
}
return mergedUpdate;
}
function AppUpdatedModalContent(props) {
const {
version,
prevVersion,
isPopulated,
error,
items,
@@ -59,7 +21,7 @@ function AppUpdatedModalContent(props) {
onModalClose
} = props;
const update = mergeUpdates(items, version, prevVersion);
const update = items[0];
return (
<ModalContent onModalClose={onModalClose}>
@@ -129,7 +91,6 @@ function AppUpdatedModalContent(props) {
AppUpdatedModalContent.propTypes = {
version: PropTypes.string.isRequired,
prevVersion: PropTypes.string,
isPopulated: PropTypes.bool.isRequired,
error: PropTypes.object,
items: PropTypes.arrayOf(PropTypes.object).isRequired,

View File

@@ -8,9 +8,8 @@ import AppUpdatedModalContent from './AppUpdatedModalContent';
function createMapStateToProps() {
return createSelector(
(state) => state.app.version,
(state) => state.app.prevVersion,
(state) => state.system.updates,
(version, prevVersion, updates) => {
(version, updates) => {
const {
isPopulated,
error,
@@ -19,7 +18,6 @@ function createMapStateToProps() {
return {
version,
prevVersion,
isPopulated,
error,
items

View File

@@ -1,49 +0,0 @@
import PropTypes from 'prop-types';
import React, { Fragment, useCallback, useEffect } from 'react';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import themes from 'Styles/Themes';
function createMapStateToProps() {
return createSelector(
(state) => state.settings.ui.item.theme || window.Readarr.theme,
(
theme
) => {
return {
theme
};
}
);
}
function ApplyTheme({ theme, children }) {
// Update the CSS Variables
const updateCSSVariables = useCallback(() => {
const arrayOfVariableKeys = Object.keys(themes[theme]);
const arrayOfVariableValues = Object.values(themes[theme]);
// Loop through each array key and set the CSS Variables
arrayOfVariableKeys.forEach((cssVariableKey, index) => {
// Based on our snippet from MDN
document.documentElement.style.setProperty(
`--${cssVariableKey}`,
arrayOfVariableValues[index]
);
});
}, [theme]);
// On Component Mount and Component Update
useEffect(() => {
updateCSSVariables(theme);
}, [updateCSSVariables, theme]);
return <Fragment>{children}</Fragment>;
}
ApplyTheme.propTypes = {
theme: PropTypes.string.isRequired,
children: PropTypes.object.isRequired
};
export default connect(createMapStateToProps)(ApplyTheme);

View File

@@ -99,7 +99,7 @@ class AuthorImage extends Component {
if (this.props.onError) {
this.props.onError();
}
};
}
onLoad = () => {
this.setState({
@@ -110,7 +110,7 @@ class AuthorImage extends Component {
if (this.props.onLoad) {
this.props.onLoad();
}
};
}
//
// Render

View File

@@ -8,5 +8,5 @@
.deleteFilesMessage {
margin-top: 20px;
color: var(--dangerColor);
color: $dangerColor;
}

View File

@@ -33,11 +33,11 @@ class DeleteAuthorModalContent extends Component {
onDeleteFilesChange = ({ value }) => {
this.setState({ deleteFiles: value });
};
}
onAddImportListExclusionChange = ({ value }) => {
this.setState({ addImportListExclusion: value });
};
}
onDeleteAuthorConfirmed = () => {
const deleteFiles = this.state.deleteFiles;
@@ -46,7 +46,7 @@ class DeleteAuthorModalContent extends Component {
this.setState({ deleteFiles: false });
this.setState({ addImportListExclusion: false });
this.props.onDeletePress(deleteFiles, addImportListExclusion);
};
}
//
// Render

View File

@@ -32,7 +32,7 @@ class DeleteAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render

View File

@@ -9,7 +9,7 @@
}
.metadataMessage {
color: var(--helpTextColor);
color: $helpTextColor;
text-align: center;
font-weight: 300;
font-size: 20px;
@@ -22,7 +22,7 @@
.tabList {
margin: 0;
padding: 0;
border-bottom: 1px solid var(--lightGray);
border-bottom: 1px solid $lightGray;
}
.tab {
@@ -37,7 +37,7 @@
}
.selectedTab {
border-bottom: 4px solid var(--linkColor);
border-bottom: 4px solid $linkColor;
}
.tabContent {
@@ -63,7 +63,7 @@
white-space: nowrap;
&:hover {
color: var(--iconButtonHoverLightColor);
color: $iconButtonHoverLightColor;
}
}

View File

@@ -99,69 +99,69 @@ class AuthorDetails extends Component {
}
this.setState({ selectedState: newSelectedState, allSelected: isAllSelected, allUnselected: isAllUnselected });
};
}
getSelectedIds = () => {
return getSelectedIds(this.state.selectedState);
};
}
//
// Listeners
onOrganizePress = () => {
this.setState({ isOrganizeModalOpen: true });
};
}
onOrganizeModalClose = () => {
this.setState({ isOrganizeModalOpen: false });
};
}
onRetagPress = () => {
this.setState({ isRetagModalOpen: true });
};
}
onRetagModalClose = () => {
this.setState({ isRetagModalOpen: false });
};
}
onInteractiveImportPress = () => {
this.setState({ isInteractiveImportModalOpen: true });
};
}
onInteractiveImportModalClose = () => {
this.setState({ isInteractiveImportModalOpen: false });
};
}
onEditAuthorPress = () => {
this.setState({ isEditAuthorModalOpen: true });
};
}
onEditAuthorModalClose = () => {
this.setState({ isEditAuthorModalOpen: false });
};
}
onDeleteAuthorPress = () => {
this.setState({
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: true
});
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
onMonitorOptionsPress = () => {
this.setState({ isMonitorOptionsModalOpen: true });
};
}
onMonitorOptionsClose = () => {
this.setState({ isMonitorOptionsModalOpen: false });
};
}
onBookEditorTogglePress = () => {
this.setState({ isEditorActive: !this.state.isEditorActive });
};
}
onExpandAllPress = () => {
const {
@@ -170,7 +170,7 @@ class AuthorDetails extends Component {
} = this.state;
this.setState(getExpandedState(selectAll(expandedState, !allExpanded)));
};
}
onExpandPress = (bookId, isExpanded) => {
this.setState((state) => {
@@ -184,32 +184,32 @@ class AuthorDetails extends Component {
return getExpandedState(newState);
});
};
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
};
}
onSelectAllPress = () => {
this.onSelectAllChange({ value: !this.state.allSelected });
};
}
onSelectedChange = (items, id, value, shiftKey = false) => {
this.setState((state) => {
return toggleSelected(state, items, id, value, shiftKey);
});
};
}
onSaveSelected = (changes) => {
this.props.onSaveSelected({
bookIds: this.getSelectedIds(),
...changes
});
};
}
onTabSelect = (index, lastIndex) => {
this.setState({ selectedTabIndex: index });
};
}
//
// Render

View File

@@ -270,7 +270,7 @@ class AuthorDetailsConnector extends Component {
this.props.fetchSeries({ authorId });
this.props.fetchBookFiles({ authorId });
this.props.fetchQueueDetails({ authorId });
};
}
unpopulate = () => {
this.props.cancelFetchReleases();
@@ -278,7 +278,7 @@ class AuthorDetailsConnector extends Component {
this.props.clearBookFiles();
this.props.clearQueueDetails();
this.props.clearReleases();
};
}
//
// Listeners
@@ -288,25 +288,25 @@ class AuthorDetailsConnector extends Component {
authorId: this.props.id,
monitored
});
};
}
onRefreshPress = () => {
this.props.executeCommand({
name: commandNames.REFRESH_AUTHOR,
authorId: this.props.id
});
};
}
onSearchPress = () => {
this.props.executeCommand({
name: commandNames.AUTHOR_SEARCH,
authorId: this.props.id
});
};
}
onSaveSelected = (payload) => {
this.props.saveBookEditor(payload);
};
}
//
// Render

View File

@@ -16,7 +16,7 @@
position: absolute;
width: 100%;
height: 100%;
background: var(--black);
background: $black;
opacity: 0.7;
}
@@ -25,7 +25,7 @@
padding: 30px;
width: 100%;
height: 100%;
color: var(--white);
color: $white;
}
.poster {
@@ -69,7 +69,7 @@
width: 40px;
&:hover {
color: var(--iconButtonHoverLightColor);
color: $iconButtonHoverLightColor;
}
}
@@ -97,7 +97,7 @@
white-space: nowrap;
&:hover {
color: var(--iconButtonHoverLightColor);
color: $iconButtonHoverLightColor;
}
}

View File

@@ -52,11 +52,11 @@ class AuthorDetailsHeader extends Component {
onOverviewMeasure = ({ height }) => {
this.setState({ overviewHeight: height });
};
}
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
};
}
//
// Render

View File

@@ -48,7 +48,7 @@ class AuthorDetailsHeaderConnector extends Component {
authorId: this.props.authorId,
monitored
});
};
}
//
// Render

View File

@@ -1,8 +1,8 @@
.bookType {
margin-bottom: 20px;
border: 1px solid var(--borderColor);
border: 1px solid $borderColor;
border-radius: 4px;
background-color: var(--cardBackgroundColor);
background-color: $white;
&:last-of-type {
margin-bottom: 0;
@@ -77,7 +77,7 @@
.books {
padding-top: 15px;
border-top: 1px solid var(--borderColor);
border-top: 1px solid $borderColor;
}
.collapseButtonContainer {
@@ -86,10 +86,10 @@
justify-content: center;
padding: 10px 15px;
width: 100%;
border-top: 1px solid var(--borderColor);
border-top: 1px solid $borderColor;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color: var(--collapseButtonBackgroundColor);
background-color: #fafafa;
}
.collapseButtonIcon {

View File

@@ -61,7 +61,7 @@ class AuthorDetailsSeason extends Component {
this.setState({ lastToggledBook: bookId });
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
};
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
const {
@@ -70,7 +70,7 @@ class AuthorDetailsSeason extends Component {
} = this.props;
return onSelectedChange(items, id, value, shiftKey);
};
}
//
// Render

View File

@@ -66,18 +66,18 @@ class AuthorDetailsSeasonConnector extends Component {
onTableOptionChange = (payload) => {
this.props.setBooksTableOption(payload);
};
}
onSortPress = (sortKey) => {
this.props.setAuthorDetailsSort({ sortKey });
};
}
onMonitorBookPress = (bookIds, monitored) => {
this.props.toggleBooksMonitored({
bookIds,
monitored
});
};
}
//
// Render

View File

@@ -1,8 +1,8 @@
.bookType {
margin-bottom: 20px;
border: 1px solid var(--borderColor);
border: 1px solid $borderColor;
border-radius: 4px;
background-color: var(--cardBackgroundColor);
background-color: $white;
&:last-of-type {
margin-bottom: 0;
@@ -77,7 +77,7 @@
.books {
padding-top: 15px;
border-top: 1px solid var(--borderColor);
border-top: 1px solid $borderColor;
}
.collapseButtonContainer {
@@ -86,10 +86,10 @@
justify-content: center;
padding: 10px 15px;
width: 100%;
border-top: 1px solid var(--borderColor);
border-top: 1px solid $borderColor;
border-bottom-right-radius: 4px;
border-bottom-left-radius: 4px;
background-color: var(--cardBackgroundColor);
background-color: #fafafa;
}
.collapseButtonIcon {

View File

@@ -73,7 +73,7 @@ class AuthorDetailsSeries extends Component {
} = this.props;
this.props.onExpandPress(id, !isExpanded);
};
}
onMonitorBookPress = (bookId, monitored, { shiftKey }) => {
const lastToggled = this.state.lastToggledBook;
@@ -91,13 +91,13 @@ class AuthorDetailsSeries extends Component {
this.setState({ lastToggledBook: bookId });
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
};
}
onMonitorSeriesPress = (monitored, { shiftKey }) => {
const bookIds = this.props.items.map((book) => book.id);
this.props.onMonitorBookPress(_.uniq(bookIds), monitored);
};
}
//
// Render

View File

@@ -81,18 +81,18 @@ class AuthorDetailsSeasonConnector extends Component {
onTableOptionChange = (payload) => {
this.props.setSeriesTableOption(payload);
};
}
onSortPress = (sortKey) => {
this.props.dispatchSetSeriesSort({ sortKey });
};
}
onMonitorBookPress = (bookIds, monitored) => {
this.props.toggleBooksMonitored({
bookIds,
monitored
});
};
}
//
// Render

View File

@@ -30,23 +30,23 @@ class BookRow extends Component {
onManualSearchPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
onEditBookPress = () => {
this.setState({ isEditBookModalOpen: true });
};
}
onEditBookModalClose = () => {
this.setState({ isEditBookModalOpen: false });
};
}
onMonitorBookPress = (monitored, options) => {
this.props.onMonitorBookPress(this.props.id, monitored, options);
};
}
//
// Render

View File

@@ -16,7 +16,7 @@ class EditAuthorModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'author' });
this.props.onModalClose();
};
}
//
// Render

View File

@@ -48,13 +48,13 @@ class EditAuthorModalContent extends Component {
onSavePress(false);
}
};
}
onMoveAuthorPress = () => {
this.setState({ isConfirmMoveModalOpen: false });
this.props.onSavePress(true);
};
}
//
// Render

View File

@@ -83,14 +83,14 @@ class EditAuthorModalContentConnector extends Component {
onInputChange = ({ name, value }) => {
this.props.dispatchSetAuthorValue({ name, value });
};
}
onSavePress = (moveFiles) => {
this.props.dispatchSaveAuthor({
id: this.props.authorId,
moveFiles
});
};
}
//
// Render

View File

@@ -30,11 +30,11 @@ class RetagAuthorModalContent extends Component {
onCheckInputChange = ({ name, value }) => {
this.setState({ [name]: value });
};
}
onRetagAuthorPress = () => {
this.props.onRetagAuthorPress(this.state.updateCovers, this.state.embedMetadata);
};
}
//
// Render

View File

@@ -45,7 +45,7 @@ class RetagAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render

View File

@@ -80,7 +80,7 @@ class AuthorEditorFooter extends Component {
default:
this.props.onSaveSelected({ [name]: value });
}
};
}
onApplyTagsPress = (tags, applyTags) => {
this.setState({
@@ -92,23 +92,23 @@ class AuthorEditorFooter extends Component {
tags,
applyTags
});
};
}
onDeleteSelectedPress = () => {
this.setState({ isDeleteAuthorModalOpen: true });
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
onTagsPress = () => {
this.setState({ isTagsModalOpen: true });
};
}
onTagsModalClose = () => {
this.setState({ isTagsModalOpen: false });
};
}
onSaveRootFolderPress = () => {
this.setState({
@@ -117,7 +117,7 @@ class AuthorEditorFooter extends Component {
});
this.props.onSaveSelected({ rootFolderPath: this.state.destinationRootFolder });
};
}
onMoveAuthorPress = () => {
this.setState({
@@ -129,7 +129,7 @@ class AuthorEditorFooter extends Component {
rootFolderPath: this.state.destinationRootFolder,
moveFiles: true
});
};
}
//
// Render
@@ -267,7 +267,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={onOrganizeAuthorPress}
>
{translate('RenameFiles')}
Rename Files
</SpinnerButton>
<SpinnerButton
@@ -277,7 +277,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={onRetagAuthorPress}
>
{translate('WriteMetadataTags')}
Write Metadata Tags
</SpinnerButton>
<SpinnerButton
@@ -286,7 +286,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isOrganizingAuthor || isRetaggingAuthor}
onPress={this.onTagsPress}
>
{translate('SetReadarrTags')}
Set Readarr Tags
</SpinnerButton>
<SpinnerButton
@@ -296,7 +296,7 @@ class AuthorEditorFooter extends Component {
isDisabled={!selectedCount || isDeleting}
onPress={this.onDeleteSelectedPress}
>
{translate('Delete')}
Delete
</SpinnerButton>
</div>

View File

@@ -16,7 +16,7 @@ class AuthorEditorRow extends Component {
onBookFolderChange = () => {
// Mock handler to satisfy `onChange` being required for `CheckInput`.
//
};
}
//
// Render

View File

@@ -9,5 +9,5 @@
.path {
margin-left: 5px;
color: var(--dangerColor);
color: $dangerColor;
}

View File

@@ -29,14 +29,14 @@ class DeleteAuthorModalContent extends Component {
onDeleteFilesChange = ({ value }) => {
this.setState({ deleteFiles: value });
};
}
onDeleteAuthorConfirmed = () => {
const deleteFiles = this.state.deleteFiles;
this.setState({ deleteFiles: false });
this.props.onDeleteSelectedPress(deleteFiles);
};
}
//
// Render

View File

@@ -43,7 +43,7 @@ class OrganizeAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render

View File

@@ -34,7 +34,7 @@ class TagsModalContent extends Component {
onInputChange = ({ name, value }) => {
this.setState({ [name]: value });
};
}
onApplyTagsPress = () => {
const {
@@ -43,7 +43,7 @@ class TagsModalContent extends Component {
} = this.state;
this.props.onApplyTagsPress(tags, applyTags);
};
}
//
// Render

View File

@@ -54,7 +54,7 @@ class AuthorHistoryContentConnector extends Component {
authorId,
bookId
});
};
}
//
// Render

View File

@@ -55,16 +55,16 @@ class AuthorHistoryRow extends Component {
onMarkAsFailedPress = () => {
this.setState({ isMarkAsFailedModalOpen: true });
};
}
onConfirmMarkAsFailed = () => {
this.props.onMarkAsFailedPress(this.props.id);
this.setState({ isMarkAsFailedModalOpen: false });
};
}
onMarkAsFailedModalClose = () => {
this.setState({ isMarkAsFailedModalOpen: false });
};
}
//
// Render

View File

@@ -99,14 +99,14 @@ class AuthorIndex extends Component {
setScrollerRef = (ref) => {
this.setState({ scroller: ref });
};
}
getSelectedIds = () => {
if (this.state.allUnselected) {
return [];
}
return getSelectedIds(this.state.selectedState);
};
}
setSelectedState() {
const {
@@ -192,19 +192,19 @@ class AuthorIndex extends Component {
onPosterOptionsPress = () => {
this.setState({ isPosterOptionsModalOpen: true });
};
}
onPosterOptionsModalClose = () => {
this.setState({ isPosterOptionsModalOpen: false });
};
}
onOverviewOptionsPress = () => {
this.setState({ isOverviewOptionsModalOpen: true });
};
}
onOverviewOptionsModalClose = () => {
this.setState({ isOverviewOptionsModalOpen: false });
};
}
onEditorTogglePress = () => {
if (this.state.isEditorActive) {
@@ -214,36 +214,36 @@ class AuthorIndex extends Component {
newState.isEditorActive = true;
this.setState(newState);
}
};
}
onJumpBarItemPress = (jumpToCharacter) => {
this.setState({ jumpToCharacter });
};
}
onSelectAllChange = ({ value }) => {
this.setState(selectAll(this.state.selectedState, value));
};
}
onSelectAllPress = () => {
this.onSelectAllChange({ value: !this.state.allSelected });
};
}
onSelectedChange = ({ id, value, shiftKey = false }) => {
this.setState((state) => {
return toggleSelected(state, this.props.items, id, value, shiftKey);
});
};
}
onSaveSelected = (changes) => {
this.props.onSaveSelected({
authorIds: this.getSelectedIds(),
...changes
});
};
}
onOrganizeAuthorPress = () => {
this.setState({ isOrganizingAuthorModalOpen: true });
};
}
onOrganizeAuthorModalClose = (organized) => {
this.setState({ isOrganizingAuthorModalOpen: false });
@@ -251,11 +251,11 @@ class AuthorIndex extends Component {
if (organized === true) {
this.onSelectAllChange({ value: false });
}
};
}
onRetagAuthorPress = () => {
this.setState({ isRetaggingAuthorModalOpen: true });
};
}
onRetagAuthorModalClose = (organized) => {
this.setState({ isRetaggingAuthorModalOpen: false });
@@ -263,14 +263,14 @@ class AuthorIndex extends Component {
if (organized === true) {
this.onSelectAllChange({ value: false });
}
};
}
onRefreshAuthorPress = () => {
const selectedIds = this.getSelectedIds();
const refreshIds = this.state.isEditorActive && selectedIds.length > 0 ? selectedIds : [];
this.props.onRefreshAuthorPress(refreshIds);
};
}
//
// Render

View File

@@ -85,15 +85,15 @@ class AuthorIndexConnector extends Component {
onViewSelect = (view) => {
this.props.dispatchSetAuthorView(view);
};
}
onSaveSelected = (payload) => {
this.props.dispatchSaveAuthorEditor(payload);
};
}
onScroll = ({ scrollTop }) => {
scrollPositions.authorIndex = scrollTop;
};
}
//
// Render

View File

@@ -21,32 +21,32 @@
.continuing {
composes: legendItemColor;
background-color: var(--primaryColor);
background-color: $primaryColor;
}
.ended {
composes: legendItemColor;
background-color: var(--successColor);
background-color: $successColor;
}
.missingMonitored {
composes: legendItemColor;
background-color: var(--dangerColor);
background-color: $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);
background: repeating-linear-gradient(90deg, color($dangerColor shade(5%)), color($dangerColor shade(5%)) 5px, color($dangerColor shade(15%)) 5px, color($dangerColor shade(15%)) 10px);
}
}
.missingUnmonitored {
composes: legendItemColor;
background-color: var(--warningColor);
background-color: $warningColor;
&:global(.colorImpaired) {
background: repeating-linear-gradient(45deg, #ffa500, #ffa500 5px, color(#ffa500 tint(15%)) 5px, color(#ffa500 tint(15%)) 10px);
background: repeating-linear-gradient(45deg, $warningColor, $warningColor 5px, color($warningColor tint(15%)) 5px, color($warningColor tint(15%)) 10px);
}
}

View File

@@ -98,14 +98,14 @@ class AuthorIndexItemConnector extends Component {
name: commandNames.REFRESH_AUTHOR,
authorId: this.props.id
});
};
}
onSearchPress = () => {
this.props.dispatchExecuteCommand({
name: commandNames.AUTHOR_SEARCH,
authorId: this.props.id
});
};
}
//
// Render

View File

@@ -3,7 +3,7 @@ $hoverScale: 1.05;
.container {
&:hover {
.content {
background-color: var(--tableRowHoverBackgroundColor);
background-color: $tableRowHoverBackgroundColor;
}
}
}
@@ -35,10 +35,10 @@ $hoverScale: 1.05;
composes: link from '~Components/Link/Link.css';
display: block;
color: var(--defaultColor);
color: $defaultColor;
&:hover {
color: var(--defaultColor);
color: $defaultColor;
text-decoration: none;
}
}
@@ -52,8 +52,8 @@ $hoverScale: 1.05;
height: 0;
border-width: 0 25px 25px 0;
border-style: solid;
border-color: transparent var(--dangerColor) transparent transparent;
color: var(--white);
border-color: transparent $dangerColor transparent transparent;
color: $white;
}
.info {

View File

@@ -51,22 +51,22 @@ class AuthorIndexOverview extends Component {
onEditAuthorPress = () => {
this.setState({ isEditAuthorModalOpen: true });
};
}
onEditAuthorModalClose = () => {
this.setState({ isEditAuthorModalOpen: false });
};
}
onDeleteAuthorPress = () => {
this.setState({
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: true
});
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
onChange = ({ value, shiftKey }) => {
const {
@@ -75,7 +75,7 @@ class AuthorIndexOverview extends Component {
} = this.props;
onSelectedChange({ id, value, shiftKey });
};
}
//
// Render

View File

@@ -123,7 +123,7 @@ class AuthorIndexOverviews extends Component {
setGridRef = (ref) => {
this._grid = ref;
};
}
calculateGrid = (width = this.state.width, isSmallScreen) => {
const {
@@ -141,7 +141,7 @@ class AuthorIndexOverviews extends Component {
posterHeight,
rowHeight
});
};
}
cellRenderer = ({ key, rowIndex, style }) => {
const {
@@ -197,14 +197,14 @@ class AuthorIndexOverviews extends Component {
/>
</div>
);
};
}
//
// Listeners
onMeasure = ({ width }) => {
this.calculateGrid(width, this.props.isSmallScreen);
};
}
//
// Render

View File

@@ -122,7 +122,7 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
}, () => {
this.props.onChangeOverviewOption({ [name]: value });
});
};
}
//
// Render

View File

@@ -5,7 +5,7 @@ $hoverScale: 1.05;
&:hover {
z-index: 2;
box-shadow: 0 0 12px var(--black);
box-shadow: 0 0 12px $black;
transition: all 200ms ease-in;
.controls {
@@ -32,7 +32,7 @@ $hoverScale: 1.05;
position: relative;
display: block;
height: 70px;
background-color: var(--defaultColor);
background-color: $defaultColor;
}
.overlayTitle {
@@ -45,13 +45,13 @@ $hoverScale: 1.05;
padding: 5px;
width: 100%;
height: 100%;
color: var(--offWhite);
color: $offWhite;
text-align: center;
font-size: 20px;
}
.nextAiring {
background-color: var(--seriesBackgroundColor);
background-color: #fafbfc;
text-align: center;
font-size: $smallFontSize;
}
@@ -59,7 +59,8 @@ $hoverScale: 1.05;
.title {
@add-mixin truncate;
background-color: var(--seriesBackgroundColor);
background-color: $defaultColor;
color: $white;
text-align: center;
font-size: $smallFontSize;
}
@@ -73,8 +74,8 @@ $hoverScale: 1.05;
height: 0;
border-width: 0 25px 25px 0;
border-style: solid;
border-color: transparent var(--dangerColor) transparent transparent;
color: var(--white);
border-color: transparent $dangerColor transparent transparent;
color: $white;
}
.editorSelect {
@@ -90,8 +91,8 @@ $hoverScale: 1.05;
left: 10px;
z-index: 3;
border-radius: 4px;
background-color: var(--readarrRed);
color: var(--white);
background-color: $themeLightColor;
color: $white;
font-size: $smallFontSize;
opacity: 0;
transition: opacity 0;

View File

@@ -35,34 +35,34 @@ class AuthorIndexPoster extends Component {
onEditAuthorPress = () => {
this.setState({ isEditAuthorModalOpen: true });
};
}
onEditAuthorModalClose = () => {
this.setState({ isEditAuthorModalOpen: false });
};
}
onDeleteAuthorPress = () => {
this.setState({
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: true
});
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
onPosterLoad = () => {
if (this.state.hasPosterError) {
this.setState({ hasPosterError: false });
}
};
}
onPosterLoadError = () => {
if (!this.state.hasPosterError) {
this.setState({ hasPosterError: true });
}
};
}
onChange = ({ value, shiftKey }) => {
const {
@@ -71,7 +71,7 @@ class AuthorIndexPoster extends Component {
} = this.props;
onSelectedChange({ id, value, shiftKey });
};
}
//
// Render

View File

@@ -1,5 +1,5 @@
.info {
background-color: var(--seriesBackgroundColor);
background-color: #fafbfc;
text-align: center;
font-size: $smallFontSize;
}

View File

@@ -171,7 +171,7 @@ class AuthorIndexPosters extends Component {
setGridRef = (ref) => {
this._grid = ref;
};
}
calculateGrid = (width = this.state.width, isSmallScreen) => {
const {
@@ -193,7 +193,7 @@ class AuthorIndexPosters extends Component {
posterHeight,
rowHeight
});
};
}
cellRenderer = ({ key, rowIndex, columnIndex, style }) => {
const {
@@ -259,14 +259,14 @@ class AuthorIndexPosters extends Component {
/>
</div>
);
};
}
//
// Listeners
onMeasure = ({ width }) => {
this.calculateGrid(width, this.props.isSmallScreen);
};
}
//
// Render

View File

@@ -93,7 +93,7 @@ class AuthorIndexPosterOptionsModalContent extends Component {
}, () => {
this.props.onChangePosterOption({ [name]: value });
});
};
}
//
// Render

View File

@@ -3,7 +3,7 @@
border-radius: 0;
background-color: #5b5b5b;
color: var(--white);
color: $white;
transition: width 200ms ease;
}

View File

@@ -27,22 +27,22 @@ class AuthorIndexActionsCell extends Component {
onEditAuthorPress = () => {
this.setState({ isEditAuthorModalOpen: true });
};
}
onEditAuthorModalClose = () => {
this.setState({ isEditAuthorModalOpen: false });
};
}
onDeleteAuthorPress = () => {
this.setState({
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: true
});
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
//
// Render

View File

@@ -31,7 +31,7 @@
position: relative;
display: block;
height: 70px;
background-color: var(--defaultColor);
background-color: $defaultColor;
}
.bannerImage {
@@ -49,7 +49,7 @@
padding: 5px;
width: 100%;
height: 100%;
color: var(--offWhite);
color: $offWhite;
text-align: center;
font-size: 20px;
}
@@ -92,7 +92,7 @@
}
.ratings {
composes: cell from '~Components/Table/Cells/VirtualTableRowCell.css';
composes: headerCell from '~Components/Table/VirtualTableHeaderCell.css';
flex: 0 0 80px;
}

View File

@@ -40,39 +40,39 @@ class AuthorIndexRow extends Component {
onEditAuthorPress = () => {
this.setState({ isEditAuthorModalOpen: true });
};
}
onEditAuthorModalClose = () => {
this.setState({ isEditAuthorModalOpen: false });
};
}
onDeleteAuthorPress = () => {
this.setState({
isEditAuthorModalOpen: false,
isDeleteAuthorModalOpen: true
});
};
}
onDeleteAuthorModalClose = () => {
this.setState({ isDeleteAuthorModalOpen: false });
};
}
onUseSceneNumberingChange = () => {
// Mock handler to satisfy `onChange` being required for `CheckInput`.
//
};
}
onBannerLoad = () => {
if (this.state.hasBannerError) {
this.setState({ hasBannerError: false });
}
};
}
onBannerLoadError = () => {
if (!this.state.hasBannerError) {
this.setState({ hasBannerError: true });
}
};
}
//
// Render

View File

@@ -78,7 +78,7 @@ class AuthorIndexTable extends Component {
/>
</VirtualTableRow>
);
};
}
//
// Render

View File

@@ -60,7 +60,7 @@ class AuthorIndexTableOptions extends Component {
}
});
});
};
}
//
// Render

View File

@@ -16,7 +16,7 @@ class MonitoringOptionsModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'authors' });
this.props.onModalClose();
};
}
//
// Render

View File

@@ -44,7 +44,7 @@ class MonitoringOptionsModalContent extends Component {
onInputChange = ({ name, value }) => {
this.setState({ [name]: value });
};
}
//
// Listeners
@@ -65,11 +65,11 @@ class MonitoringOptionsModalContent extends Component {
if (!isSaving) {
this.onModalClose();
}
};
}
onModalClose = () => {
this.props.onModalClose();
};
}
//
// Render

View File

@@ -42,14 +42,14 @@ class MonitoringOptionsModalContentConnector extends Component {
onInputChange = ({ name, value }) => {
this.setState({ name, value });
};
}
onSavePress = ({ monitor }) => {
this.props.dispatchUpdateMonitoringOptions({
id: this.props.authorId,
monitor
});
};
}
//
// Render

View File

@@ -25,11 +25,11 @@ class BookSearchCell extends Component {
onManualSearchPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
//
// Render

View File

@@ -2,7 +2,7 @@
composes: link from '~Components/Link/Link.css';
&:hover {
color: var(--linkHoverColor);
color: $linkHoverColor;
text-decoration: underline;
}
}

View File

@@ -8,5 +8,5 @@
.deleteFilesMessage {
margin-top: 20px;
color: var(--dangerColor);
color: $dangerColor;
}

View File

@@ -32,11 +32,11 @@ class DeleteBookModalContent extends Component {
onDeleteFilesChange = ({ value }) => {
this.setState({ deleteFiles: value });
};
}
onAddImportListExclusionChange = ({ value }) => {
this.setState({ addImportListExclusion: value });
};
}
onDeleteBookConfirmed = () => {
const deleteFiles = this.state.deleteFiles;
@@ -45,7 +45,7 @@ class DeleteBookModalContent extends Component {
this.setState({ deleteFiles: false });
this.setState({ addImportListExclusion: false });
this.props.onDeletePress(deleteFiles, addImportListExclusion);
};
}
//
// Render

View File

@@ -36,7 +36,7 @@ class DeleteBookModalContentConnector extends Component {
this.props.onModalClose(true);
this.props.push(`${window.Readarr.urlBase}/author/${this.props.authorSlug}`);
};
}
//
// Render

View File

@@ -9,7 +9,7 @@
.tabList {
margin: 0;
padding: 0;
border-bottom: 1px solid var(--lightGray);
border-bottom: 1px solid $lightGray;
}
.tab {
@@ -24,7 +24,7 @@
}
.selectedTab {
border-bottom: 4px solid var(--linkColor);
border-bottom: 4px solid $linkColor;
}
.tabContent {
@@ -54,7 +54,7 @@
white-space: nowrap;
&:hover {
color: var(--iconButtonHoverLightColor);
color: $iconButtonHoverLightColor;
}
}

View File

@@ -45,42 +45,42 @@ class BookDetails extends Component {
onOrganizePress = () => {
this.setState({ isOrganizeModalOpen: true });
};
}
onOrganizeModalClose = () => {
this.setState({ isOrganizeModalOpen: false });
};
}
onRetagPress = () => {
this.setState({ isRetagModalOpen: true });
};
}
onRetagModalClose = () => {
this.setState({ isRetagModalOpen: false });
};
}
onEditBookPress = () => {
this.setState({ isEditBookModalOpen: true });
};
}
onEditBookModalClose = () => {
this.setState({ isEditBookModalOpen: false });
};
}
onDeleteBookPress = () => {
this.setState({
isEditBookModalOpen: false,
isDeleteBookModalOpen: true
});
};
}
onDeleteBookModalClose = () => {
this.setState({ isDeleteBookModalOpen: false });
};
}
onTabSelect = (index, lastIndex) => {
this.setState({ selectedTabIndex: index });
};
}
//
// Render

View File

@@ -8,7 +8,6 @@ import * as commandNames from 'Commands/commandNames';
import { toggleBooksMonitored } from 'Store/Actions/bookActions';
import { clearBookFiles, fetchBookFiles } from 'Store/Actions/bookFileActions';
import { executeCommand } from 'Store/Actions/commandActions';
import { clearEditions, fetchEditions } from 'Store/Actions/editionActions';
import { cancelFetchReleases, clearReleases } from 'Store/Actions/releaseActions';
import createAllAuthorSelector from 'Store/Selectors/createAllAuthorsSelector';
import createCommandsSelector from 'Store/Selectors/createCommandsSelector';
@@ -44,12 +43,11 @@ function createMapStateToProps() {
(state, { titleSlug }) => titleSlug,
selectBookFiles,
(state) => state.books,
(state) => state.editions,
createAllAuthorSelector(),
createCommandsSelector(),
createUISettingsSelector(),
createDimensionsSelector(),
(titleSlug, bookFiles, books, editions, authors, commands, uiSettings, dimensions) => {
(titleSlug, bookFiles, books, authors, commands, uiSettings, dimensions) => {
const book = books.items.find((b) => b.titleSlug === titleSlug);
const author = authors.find((a) => a.id === book.authorId);
const sortedBooks = books.items.filter((b) => b.authorId === book.authorId);
@@ -81,8 +79,8 @@ function createMapStateToProps() {
isRefreshingCommand.body.bookId === book.id
);
const isFetching = isBookFilesFetching || editions.isFetching;
const isPopulated = isBookFilesPopulated && editions.isPopulated;
const isFetching = isBookFilesFetching;
const isPopulated = isBookFilesPopulated;
return {
...book,
@@ -106,8 +104,6 @@ const mapDispatchToProps = {
executeCommand,
fetchBookFiles,
clearBookFiles,
fetchEditions,
clearEditions,
clearReleases,
cancelFetchReleases,
toggleBooksMonitored
@@ -125,8 +121,7 @@ class BookDetailsConnector extends Component {
}
componentDidUpdate(prevProps) {
if (prevProps.id !== this.props.id ||
!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) ||
if (!_.isEqual(getMonitoredEditions(prevProps), getMonitoredEditions(this.props)) ||
(prevProps.anyReleaseOk === false && this.props.anyReleaseOk === true)) {
this.unpopulate();
this.populate();
@@ -145,15 +140,13 @@ class BookDetailsConnector extends Component {
const bookId = this.props.id;
this.props.fetchBookFiles({ bookId });
this.props.fetchEditions({ bookId });
};
}
unpopulate = () => {
this.props.cancelFetchReleases();
this.props.clearReleases();
this.props.clearBookFiles();
this.props.clearEditions();
};
}
//
// Listeners
@@ -163,21 +156,21 @@ class BookDetailsConnector extends Component {
bookIds: [this.props.id],
monitored
});
};
}
onRefreshPress = () => {
this.props.executeCommand({
name: commandNames.REFRESH_BOOK,
bookId: this.props.id
});
};
}
onSearchPress = () => {
this.props.executeCommand({
name: commandNames.BOOK_SEARCH,
bookIds: [this.props.id]
});
};
}
//
// Render
@@ -202,8 +195,6 @@ BookDetailsConnector.propTypes = {
titleSlug: PropTypes.string.isRequired,
fetchBookFiles: PropTypes.func.isRequired,
clearBookFiles: PropTypes.func.isRequired,
fetchEditions: PropTypes.func.isRequired,
clearEditions: PropTypes.func.isRequired,
clearReleases: PropTypes.func.isRequired,
cancelFetchReleases: PropTypes.func.isRequired,
toggleBooksMonitored: PropTypes.func.isRequired,

View File

@@ -16,7 +16,7 @@
position: absolute;
width: 100%;
height: 100%;
background: var(--black);
background: $black;
opacity: 0.7;
}
@@ -25,7 +25,7 @@
padding: 30px;
width: 100%;
height: 100%;
color: var(--white);
color: $white;
}
.cover {
@@ -69,7 +69,7 @@
width: 40px;
&:hover {
color: var(--iconButtonHoverLightColor);
color: $iconButtonHoverLightColor;
}
}

View File

@@ -48,11 +48,11 @@ class BookDetailsHeader extends Component {
onOverviewMeasure = ({ height }) => {
this.setState({ overviewHeight: height });
};
}
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
};
}
//
// Render

View File

@@ -8,25 +8,15 @@ import createDimensionsSelector from 'Store/Selectors/createDimensionsSelector';
import createUISettingsSelector from 'Store/Selectors/createUISettingsSelector';
import BookDetailsHeader from './BookDetailsHeader';
const selectOverview = createSelector(
(state) => state.editions,
(editions) => {
const monitored = editions.items.find((e) => e.monitored === true);
return monitored?.overview;
}
);
function createMapStateToProps() {
return createSelector(
createBookSelector(),
selectOverview,
createUISettingsSelector(),
createDimensionsSelector(),
(book, overview, uiSettings, dimensions) => {
(book, uiSettings, dimensions) => {
return {
...book,
overview,
shortDateFormat: uiSettings.shortDateFormat,
isSmallScreen: dimensions.isSmallScreen
};
@@ -48,7 +38,7 @@ class BookDetailsHeaderConnector extends Component {
bookIds: [this.props.bookId],
monitored
});
};
}
//
// Render

View File

@@ -64,7 +64,7 @@ class BookDetailsPageConnector extends Component {
populate = () => {
this.setState({ hasMounted: true });
};
}
//
// Render

View File

@@ -16,7 +16,7 @@ class EditBookModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'books' });
this.props.onModalClose();
};
}
//
// Render

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