mirror of
https://github.com/Prowlarr/Prowlarr.git
synced 2025-09-17 17:14:18 +02:00
New: Bulk Enable/Disable
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
|
import SelectInput from 'Components/Form/SelectInput';
|
||||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||||
import { kinds } from 'Helpers/Props';
|
import { kinds } from 'Helpers/Props';
|
||||||
@@ -20,6 +21,7 @@ class IndexerEditorFooter extends Component {
|
|||||||
super(props, context);
|
super(props, context);
|
||||||
|
|
||||||
this.state = {
|
this.state = {
|
||||||
|
enable: NO_CHANGE,
|
||||||
savingTags: false,
|
savingTags: false,
|
||||||
isDeleteMovieModalOpen: false,
|
isDeleteMovieModalOpen: false,
|
||||||
isTagsModalOpen: false
|
isTagsModalOpen: false
|
||||||
@@ -34,6 +36,7 @@ class IndexerEditorFooter extends Component {
|
|||||||
|
|
||||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||||
this.setState({
|
this.setState({
|
||||||
|
enable: NO_CHANGE,
|
||||||
savingTags: false
|
savingTags: false
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -95,13 +98,35 @@ class IndexerEditorFooter extends Component {
|
|||||||
} = this.props;
|
} = this.props;
|
||||||
|
|
||||||
const {
|
const {
|
||||||
|
enable,
|
||||||
savingTags,
|
savingTags,
|
||||||
isTagsModalOpen,
|
isTagsModalOpen,
|
||||||
isDeleteMovieModalOpen
|
isDeleteMovieModalOpen
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
|
const enableOptions = [
|
||||||
|
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
|
||||||
|
{ key: 'true', value: translate('Enabled') },
|
||||||
|
{ key: 'false', value: translate('Disabled') }
|
||||||
|
];
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<PageContentFooter>
|
<PageContentFooter>
|
||||||
|
<div className={styles.inputContainer}>
|
||||||
|
<IndexerEditorFooterLabel
|
||||||
|
label={translate('EnableIndexer')}
|
||||||
|
isSaving={isSaving && enable !== NO_CHANGE}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<SelectInput
|
||||||
|
name="enable"
|
||||||
|
value={enable}
|
||||||
|
values={enableOptions}
|
||||||
|
isDisabled={!selectedCount}
|
||||||
|
onChange={this.onInputChange}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div className={styles.buttonContainer}>
|
<div className={styles.buttonContainer}>
|
||||||
<div className={styles.buttonContainerContent}>
|
<div className={styles.buttonContainerContent}>
|
||||||
<IndexerEditorFooterLabel
|
<IndexerEditorFooterLabel
|
||||||
|
@@ -246,7 +246,7 @@ class IndexerIndex extends Component {
|
|||||||
|
|
||||||
onSaveSelected = (changes) => {
|
onSaveSelected = (changes) => {
|
||||||
this.props.onSaveSelected({
|
this.props.onSaveSelected({
|
||||||
movieIds: this.getSelectedIds(),
|
indexerIds: this.getSelectedIds(),
|
||||||
...changes
|
...changes
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -290,7 +290,7 @@ class IndexerIndex extends Component {
|
|||||||
allUnselected
|
allUnselected
|
||||||
} = this.state;
|
} = this.state;
|
||||||
|
|
||||||
const selectedMovieIds = this.getSelectedIds();
|
const selectedIndexerIds = this.getSelectedIds();
|
||||||
|
|
||||||
const ViewComponent = getViewComponent();
|
const ViewComponent = getViewComponent();
|
||||||
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
||||||
@@ -448,8 +448,8 @@ class IndexerIndex extends Component {
|
|||||||
{
|
{
|
||||||
isLoaded && isMovieEditorActive &&
|
isLoaded && isMovieEditorActive &&
|
||||||
<IndexerEditorFooter
|
<IndexerEditorFooter
|
||||||
indexerIds={selectedMovieIds}
|
indexerIds={selectedIndexerIds}
|
||||||
selectedCount={selectedMovieIds.length}
|
selectedCount={selectedIndexerIds.length}
|
||||||
isSaving={isSaving}
|
isSaving={isSaving}
|
||||||
saveError={saveError}
|
saveError={saveError}
|
||||||
isDeleting={isDeleting}
|
isDeleting={isDeleting}
|
||||||
|
@@ -182,7 +182,7 @@ export const actionHandlers = handleThunks({
|
|||||||
}));
|
}));
|
||||||
|
|
||||||
const promise = createAjaxRequest({
|
const promise = createAjaxRequest({
|
||||||
url: '/movie/editor',
|
url: '/indexer/editor',
|
||||||
method: 'PUT',
|
method: 'PUT',
|
||||||
data: JSON.stringify(payload),
|
data: JSON.stringify(payload),
|
||||||
dataType: 'json'
|
dataType: 'json'
|
||||||
@@ -190,11 +190,11 @@ export const actionHandlers = handleThunks({
|
|||||||
|
|
||||||
promise.done((data) => {
|
promise.done((data) => {
|
||||||
dispatch(batchActions([
|
dispatch(batchActions([
|
||||||
...data.map((movie) => {
|
...data.map((indexer) => {
|
||||||
return updateItem({
|
return updateItem({
|
||||||
id: movie.id,
|
id: indexer.id,
|
||||||
section: 'movies',
|
section: 'indexers',
|
||||||
...movie
|
...indexer
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
|
|
||||||
|
@@ -12,6 +12,7 @@ namespace NzbDrone.Core.ThingiProvider
|
|||||||
TProviderDefinition Get(int id);
|
TProviderDefinition Get(int id);
|
||||||
TProviderDefinition Create(TProviderDefinition definition);
|
TProviderDefinition Create(TProviderDefinition definition);
|
||||||
void Update(TProviderDefinition definition);
|
void Update(TProviderDefinition definition);
|
||||||
|
void Update(IEnumerable<TProviderDefinition> definitions);
|
||||||
void Delete(int id);
|
void Delete(int id);
|
||||||
IEnumerable<TProviderDefinition> GetDefaultDefinitions();
|
IEnumerable<TProviderDefinition> GetDefaultDefinitions();
|
||||||
IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition);
|
IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition);
|
||||||
|
@@ -109,6 +109,11 @@ namespace NzbDrone.Core.ThingiProvider
|
|||||||
_eventAggregator.PublishEvent(new ProviderUpdatedEvent<TProvider>(definition));
|
_eventAggregator.PublishEvent(new ProviderUpdatedEvent<TProvider>(definition));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public virtual void Update(IEnumerable<TProviderDefinition> definitions)
|
||||||
|
{
|
||||||
|
_providerRepository.UpdateMany(definitions.ToList());
|
||||||
|
}
|
||||||
|
|
||||||
public void Delete(int id)
|
public void Delete(int id)
|
||||||
{
|
{
|
||||||
_providerRepository.Delete(id);
|
_providerRepository.Delete(id);
|
||||||
|
@@ -1,3 +1,5 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
using Nancy;
|
using Nancy;
|
||||||
using NzbDrone.Core.Indexers;
|
using NzbDrone.Core.Indexers;
|
||||||
using NzbDrone.Core.Messaging.Commands;
|
using NzbDrone.Core.Messaging.Commands;
|
||||||
@@ -7,22 +9,68 @@ namespace Prowlarr.Api.V1.Indexers
|
|||||||
{
|
{
|
||||||
public class IndexerEditorModule : ProwlarrV1Module
|
public class IndexerEditorModule : ProwlarrV1Module
|
||||||
{
|
{
|
||||||
private readonly IIndexerFactory _movieService;
|
private readonly IIndexerFactory _indexerService;
|
||||||
private readonly IManageCommandQueue _commandQueueManager;
|
private readonly IManageCommandQueue _commandQueueManager;
|
||||||
|
public static readonly IndexerResourceMapper ResourceMapper = new IndexerResourceMapper();
|
||||||
|
|
||||||
public IndexerEditorModule(IIndexerFactory movieService, IManageCommandQueue commandQueueManager)
|
public IndexerEditorModule(IIndexerFactory indexerService, IManageCommandQueue commandQueueManager)
|
||||||
: base("/indexer/editor")
|
: base("/indexer/editor")
|
||||||
{
|
{
|
||||||
_movieService = movieService;
|
_indexerService = indexerService;
|
||||||
_commandQueueManager = commandQueueManager;
|
_commandQueueManager = commandQueueManager;
|
||||||
|
Put("/", movie => SaveAll());
|
||||||
Delete("/", movie => DeleteIndexers());
|
Delete("/", movie => DeleteIndexers());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private object SaveAll()
|
||||||
|
{
|
||||||
|
var resource = Request.Body.FromJson<IndexerEditorResource>();
|
||||||
|
var indexersToUpdate = _indexerService.All().Where(x => resource.IndexerIds.Contains(x.Id));
|
||||||
|
|
||||||
|
foreach (var indexer in indexersToUpdate)
|
||||||
|
{
|
||||||
|
if (resource.Enable.HasValue)
|
||||||
|
{
|
||||||
|
indexer.Enable = resource.Enable.Value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (resource.Tags != null)
|
||||||
|
{
|
||||||
|
var newTags = resource.Tags;
|
||||||
|
var applyTags = resource.ApplyTags;
|
||||||
|
|
||||||
|
switch (applyTags)
|
||||||
|
{
|
||||||
|
case ApplyTags.Add:
|
||||||
|
newTags.ForEach(t => indexer.Tags.Add(t));
|
||||||
|
break;
|
||||||
|
case ApplyTags.Remove:
|
||||||
|
newTags.ForEach(t => indexer.Tags.Remove(t));
|
||||||
|
break;
|
||||||
|
case ApplyTags.Replace:
|
||||||
|
indexer.Tags = new HashSet<int>(newTags);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
_indexerService.Update(indexersToUpdate);
|
||||||
|
|
||||||
|
var indexers = _indexerService.All();
|
||||||
|
|
||||||
|
foreach (var definition in indexers)
|
||||||
|
{
|
||||||
|
_indexerService.SetProviderCharacteristics(definition);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseWithCode(ResourceMapper.ToResource(indexers), HttpStatusCode.Accepted);
|
||||||
|
}
|
||||||
|
|
||||||
private object DeleteIndexers()
|
private object DeleteIndexers()
|
||||||
{
|
{
|
||||||
var resource = Request.Body.FromJson<IndexerEditorResource>();
|
var resource = Request.Body.FromJson<IndexerEditorResource>();
|
||||||
|
|
||||||
_movieService.DeleteIndexers(resource.IndexerIds);
|
_indexerService.DeleteIndexers(resource.IndexerIds);
|
||||||
|
|
||||||
return new object();
|
return new object();
|
||||||
}
|
}
|
||||||
|
@@ -5,5 +5,15 @@ namespace Prowlarr.Api.V1.Indexers
|
|||||||
public class IndexerEditorResource
|
public class IndexerEditorResource
|
||||||
{
|
{
|
||||||
public List<int> IndexerIds { get; set; }
|
public List<int> IndexerIds { get; set; }
|
||||||
|
public bool? Enable { get; set; }
|
||||||
|
public List<int> Tags { get; set; }
|
||||||
|
public ApplyTags ApplyTags { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ApplyTags
|
||||||
|
{
|
||||||
|
Add,
|
||||||
|
Remove,
|
||||||
|
Replace
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -134,5 +134,10 @@ namespace Prowlarr.Api.V1.Indexers
|
|||||||
|
|
||||||
return field;
|
return field;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public List<IndexerResource> ToResource(IEnumerable<IndexerDefinition> models)
|
||||||
|
{
|
||||||
|
return models.Select(ToResource).ToList();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user