Compare commits

..

1 Commits

Author SHA1 Message Date
Qstick 1c0943449b Fixed: Validate if equals or child for startup folder
(cherry picked from commit 0991cfe27efd6ddb533227b25754661e18d7e9ad)
2022-06-12 16:42:12 +00:00
853 changed files with 6692 additions and 12489 deletions
+2 -4
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
+2 -2
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:
-132
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
-9
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)
-8
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.
+3 -115
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.300'
innoVersion: '6.2.0'
windowsImage: 'windows-2022'
linuxImage: 'ubuntu-20.04'
@@ -530,57 +530,6 @@ stages:
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
dependsOn: Packages
@@ -648,66 +597,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:
@@ -730,7 +619,7 @@ stages:
inputs:
buildType: 'current'
artifactName: Packages
itemPattern: '**/$(pattern)'
itemPattern: '/$(pattern)'
targetPath: $(Build.ArtifactStagingDirectory)
- bash: |
mkdir -p ${BUILD_ARTIFACTSTAGINGDIRECTORY}/bin
@@ -1050,4 +939,3 @@ stages:
SYSTEM_ACCESSTOKEN: $(System.AccessToken)
DISCORDCHANNELID: $(discordChannelId)
DISCORDWEBHOOKKEY: $(discordWebhookKey)
DISCORDTHREADID: $(discordThreadId)
+1 -4
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: [
{
+1
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',
+6 -6
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
@@ -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
@@ -30,11 +30,11 @@ class BlocklistRow extends Component {
onDetailsPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
//
// Render
@@ -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
+2 -12
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
@@ -49,7 +49,7 @@ class HistoryRowConnector extends Component {
onMarkAsFailedPress = () => {
this.props.markAsFailed({ id: this.props.id });
};
}
//
// Render
@@ -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;
}
+17 -31
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>
+11 -11
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
+1 -1
View File
@@ -42,7 +42,7 @@ class QueueOptions extends Component {
[name]: value
});
});
};
}
//
// Render
+5 -5
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
@@ -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
@@ -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
@@ -37,34 +37,34 @@ class RemoveQueueItemsModal 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
-3
View File
@@ -4,7 +4,6 @@ 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 }) {
@@ -12,11 +11,9 @@ function App({ store, history }) {
<DocumentTitle title={window.Readarr.instanceName}>
<Provider store={store}>
<ConnectedRouter history={history}>
<ApplyTheme>
<PageConnector>
<AppRoutes app={App} />
</PageConnector>
</ApplyTheme>
</ConnectedRouter>
</Provider>
</DocumentTitle>
+2 -2
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
+1 -40
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,
@@ -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
-49
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);
+2 -2
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
@@ -8,5 +8,5 @@
.deleteFilesMessage {
margin-top: 20px;
color: var(--dangerColor);
color: $dangerColor;
}
@@ -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
@@ -32,7 +32,7 @@ class DeleteAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render
@@ -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;
}
}
+22 -22
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
@@ -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
@@ -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;
}
}
@@ -52,11 +52,11 @@ class AuthorDetailsHeader extends Component {
onOverviewMeasure = ({ height }) => {
this.setState({ overviewHeight: height });
};
}
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
};
}
//
// Render
@@ -48,7 +48,7 @@ class AuthorDetailsHeaderConnector extends Component {
authorId: this.props.authorId,
monitored
});
};
}
//
// Render
@@ -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 {
@@ -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
@@ -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
@@ -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 {
@@ -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
@@ -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
+5 -5
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
@@ -16,7 +16,7 @@ class EditAuthorModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'author' });
this.props.onModalClose();
};
}
//
// Render
@@ -48,13 +48,13 @@ class EditAuthorModalContent extends Component {
onSavePress(false);
}
};
}
onMoveAuthorPress = () => {
this.setState({ isConfirmMoveModalOpen: false });
this.props.onSavePress(true);
};
}
//
// Render
@@ -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
@@ -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
@@ -45,7 +45,7 @@ class RetagAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render
@@ -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
@@ -16,7 +16,7 @@ class AuthorEditorRow extends Component {
onBookFolderChange = () => {
// Mock handler to satisfy `onChange` being required for `CheckInput`.
//
};
}
//
// Render
@@ -9,5 +9,5 @@
.path {
margin-left: 5px;
color: var(--dangerColor);
color: $dangerColor;
}
@@ -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
@@ -43,7 +43,7 @@ class OrganizeAuthorModalContentConnector extends Component {
});
this.props.onModalClose(true);
};
}
//
// Render
@@ -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
@@ -54,7 +54,7 @@ class AuthorHistoryContentConnector extends Component {
authorId,
bookId
});
};
}
//
// Render
@@ -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
+17 -17
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
@@ -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
@@ -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);
}
}
@@ -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
@@ -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 {
@@ -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
@@ -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
@@ -122,7 +122,7 @@ class AuthorIndexOverviewOptionsModalContent extends Component {
}, () => {
this.props.onChangeOverviewOption({ [name]: value });
});
};
}
//
// Render
@@ -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;
@@ -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
@@ -1,5 +1,5 @@
.info {
background-color: var(--seriesBackgroundColor);
background-color: #fafbfc;
text-align: center;
font-size: $smallFontSize;
}
@@ -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
@@ -93,7 +93,7 @@ class AuthorIndexPosterOptionsModalContent extends Component {
}, () => {
this.props.onChangePosterOption({ [name]: value });
});
};
}
//
// Render
@@ -3,7 +3,7 @@
border-radius: 0;
background-color: #5b5b5b;
color: var(--white);
color: $white;
transition: width 200ms ease;
}
@@ -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
@@ -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;
}
@@ -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
@@ -78,7 +78,7 @@ class AuthorIndexTable extends Component {
/>
</VirtualTableRow>
);
};
}
//
// Render
@@ -60,7 +60,7 @@ class AuthorIndexTableOptions extends Component {
}
});
});
};
}
//
// Render
@@ -16,7 +16,7 @@ class MonitoringOptionsModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'authors' });
this.props.onModalClose();
};
}
//
// Render
@@ -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
@@ -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
+2 -2
View File
@@ -25,11 +25,11 @@ class BookSearchCell extends Component {
onManualSearchPress = () => {
this.setState({ isDetailsModalOpen: true });
};
}
onDetailsModalClose = () => {
this.setState({ isDetailsModalOpen: false });
};
}
//
// Render
+1 -1
View File
@@ -2,7 +2,7 @@
composes: link from '~Components/Link/Link.css';
&:hover {
color: var(--linkHoverColor);
color: $linkHoverColor;
text-decoration: underline;
}
}
@@ -8,5 +8,5 @@
.deleteFilesMessage {
margin-top: 20px;
color: var(--dangerColor);
color: $dangerColor;
}
@@ -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
@@ -36,7 +36,7 @@ class DeleteBookModalContentConnector extends Component {
this.props.onModalClose(true);
this.props.push(`${window.Readarr.urlBase}/author/${this.props.authorSlug}`);
};
}
//
// Render
+3 -3
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;
}
}
+9 -9
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
@@ -146,14 +146,14 @@ class BookDetailsConnector extends Component {
this.props.fetchBookFiles({ bookId });
this.props.fetchEditions({ bookId });
};
}
unpopulate = () => {
this.props.cancelFetchReleases();
this.props.clearReleases();
this.props.clearBookFiles();
this.props.clearEditions();
};
}
//
// Listeners
@@ -163,21 +163,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
@@ -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;
}
}
@@ -48,11 +48,11 @@ class BookDetailsHeader extends Component {
onOverviewMeasure = ({ height }) => {
this.setState({ overviewHeight: height });
};
}
onTitleMeasure = ({ width }) => {
this.setState({ titleWidth: width });
};
}
//
// Render
@@ -48,7 +48,7 @@ class BookDetailsHeaderConnector extends Component {
bookIds: [this.props.bookId],
monitored
});
};
}
//
// Render
@@ -64,7 +64,7 @@ class BookDetailsPageConnector extends Component {
populate = () => {
this.setState({ hasMounted: true });
};
}
//
// Render
@@ -16,7 +16,7 @@ class EditBookModalConnector extends Component {
onModalClose = () => {
this.props.clearPendingChanges({ section: 'books' });
this.props.onModalClose();
};
}
//
// Render
@@ -27,7 +27,7 @@ class EditBookModalContent extends Component {
onSavePress(false);
};
}
//
// Render
@@ -76,7 +76,7 @@ class EditBookModalContentConnector extends Component {
onInputChange = ({ name, value }) => {
this.props.dispatchSetBookValue({ name, value });
};
}
onSavePress = () => {
this.props.dispatchSaveBook({
@@ -85,7 +85,7 @@ class EditBookModalContentConnector extends Component {
this.props.dispatchSaveEditions({
id: this.props.bookId
});
};
}
//
// Render
+3 -3
View File
@@ -62,15 +62,15 @@ class BookEditorFooter extends Component {
default:
this.props.onSaveSelected({ [name]: value });
}
};
}
onDeleteSelectedPress = () => {
this.setState({ isDeleteBookModalOpen: true });
};
}
onDeleteBookModalClose = () => {
this.setState({ isDeleteBookModalOpen: false });
};
}
//
// Render
@@ -5,5 +5,5 @@
.deleteFilesMessage {
margin-top: 20px;
color: var(--dangerColor);
color: $dangerColor;
}
@@ -31,11 +31,11 @@ class DeleteBookModalContent extends Component {
onDeleteFilesChange = ({ value }) => {
this.setState({ deleteFiles: value });
};
}
onAddImportListExclusionChange = ({ value }) => {
this.setState({ addImportListExclusion: value });
};
}
onDeleteBookConfirmed = () => {
const {
@@ -45,7 +45,7 @@ class DeleteBookModalContent extends Component {
this.setState({ deleteFiles: false });
this.props.onDeleteSelectedPress(deleteFiles, addImportListExclusion);
};
}
//
// Render
+18 -18
View File
@@ -97,14 +97,14 @@ class BookIndex extends Component {
setScrollerRef = (ref) => {
this.setState({ scroller: ref });
};
}
getSelectedIds = () => {
if (this.state.allUnselected) {
return [];
}
return getSelectedIds(this.state.selectedState);
};
}
setSelectedState() {
const {
@@ -191,19 +191,19 @@ class BookIndex 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) {
@@ -213,55 +213,55 @@ class BookIndex 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({
bookIds: this.getSelectedIds(),
...changes
});
};
}
onSearchPress = () => {
this.setState({ isConfirmSearchModalOpen: true });
};
}
onRefreshBookPress = () => {
const selectedIds = this.getSelectedIds();
const refreshIds = this.state.isEditorActive && selectedIds.length > 0 ? selectedIds : [];
this.props.onRefreshBookPress(refreshIds);
};
}
onSearchConfirmed = () => {
const selectedBookIds = this.getSelectedIds();
const searchIds = this.state.isEditorActive && selectedBookIds.length > 0 ? selectedBookIds : this.props.items.map((m) => m.id);
const selectedMovieIds = this.getSelectedIds();
const searchIds = this.state.isMovieEditorActive && selectedMovieIds.length > 0 ? selectedMovieIds : this.props.items.map((m) => m.id);
this.props.onSearchPress(searchIds);
this.setState({ isConfirmSearchModalOpen: false });
};
}
onConfirmSearchModalClose = () => {
this.setState({ isConfirmSearchModalOpen: false });
};
}
//
// Render
@@ -94,15 +94,15 @@ class BookIndexConnector extends Component {
onViewSelect = (view) => {
this.props.dispatchSetBookView(view);
};
}
onSaveSelected = (payload) => {
this.props.dispatchSaveBookEditor(payload);
};
}
onScroll = ({ scrollTop }) => {
scrollPositions.bookIndex = scrollTop;
};
}
//
// Render
+6 -6
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);
}
}

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