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 React, { Component } from 'react';
|
||||
import SelectInput from 'Components/Form/SelectInput';
|
||||
import SpinnerButton from 'Components/Link/SpinnerButton';
|
||||
import PageContentFooter from 'Components/Page/PageContentFooter';
|
||||
import { kinds } from 'Helpers/Props';
|
||||
@@ -20,6 +21,7 @@ class IndexerEditorFooter extends Component {
|
||||
super(props, context);
|
||||
|
||||
this.state = {
|
||||
enable: NO_CHANGE,
|
||||
savingTags: false,
|
||||
isDeleteMovieModalOpen: false,
|
||||
isTagsModalOpen: false
|
||||
@@ -34,6 +36,7 @@ class IndexerEditorFooter extends Component {
|
||||
|
||||
if (prevProps.isSaving && !isSaving && !saveError) {
|
||||
this.setState({
|
||||
enable: NO_CHANGE,
|
||||
savingTags: false
|
||||
});
|
||||
}
|
||||
@@ -95,13 +98,35 @@ class IndexerEditorFooter extends Component {
|
||||
} = this.props;
|
||||
|
||||
const {
|
||||
enable,
|
||||
savingTags,
|
||||
isTagsModalOpen,
|
||||
isDeleteMovieModalOpen
|
||||
} = this.state;
|
||||
|
||||
const enableOptions = [
|
||||
{ key: NO_CHANGE, value: translate('NoChange'), disabled: true },
|
||||
{ key: 'true', value: translate('Enabled') },
|
||||
{ key: 'false', value: translate('Disabled') }
|
||||
];
|
||||
|
||||
return (
|
||||
<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.buttonContainerContent}>
|
||||
<IndexerEditorFooterLabel
|
||||
|
@@ -246,7 +246,7 @@ class IndexerIndex extends Component {
|
||||
|
||||
onSaveSelected = (changes) => {
|
||||
this.props.onSaveSelected({
|
||||
movieIds: this.getSelectedIds(),
|
||||
indexerIds: this.getSelectedIds(),
|
||||
...changes
|
||||
});
|
||||
}
|
||||
@@ -290,7 +290,7 @@ class IndexerIndex extends Component {
|
||||
allUnselected
|
||||
} = this.state;
|
||||
|
||||
const selectedMovieIds = this.getSelectedIds();
|
||||
const selectedIndexerIds = this.getSelectedIds();
|
||||
|
||||
const ViewComponent = getViewComponent();
|
||||
const isLoaded = !!(!error && isPopulated && items.length && scroller);
|
||||
@@ -448,8 +448,8 @@ class IndexerIndex extends Component {
|
||||
{
|
||||
isLoaded && isMovieEditorActive &&
|
||||
<IndexerEditorFooter
|
||||
indexerIds={selectedMovieIds}
|
||||
selectedCount={selectedMovieIds.length}
|
||||
indexerIds={selectedIndexerIds}
|
||||
selectedCount={selectedIndexerIds.length}
|
||||
isSaving={isSaving}
|
||||
saveError={saveError}
|
||||
isDeleting={isDeleting}
|
||||
|
@@ -182,7 +182,7 @@ export const actionHandlers = handleThunks({
|
||||
}));
|
||||
|
||||
const promise = createAjaxRequest({
|
||||
url: '/movie/editor',
|
||||
url: '/indexer/editor',
|
||||
method: 'PUT',
|
||||
data: JSON.stringify(payload),
|
||||
dataType: 'json'
|
||||
@@ -190,11 +190,11 @@ export const actionHandlers = handleThunks({
|
||||
|
||||
promise.done((data) => {
|
||||
dispatch(batchActions([
|
||||
...data.map((movie) => {
|
||||
...data.map((indexer) => {
|
||||
return updateItem({
|
||||
id: movie.id,
|
||||
section: 'movies',
|
||||
...movie
|
||||
id: indexer.id,
|
||||
section: 'indexers',
|
||||
...indexer
|
||||
});
|
||||
}),
|
||||
|
||||
|
@@ -12,6 +12,7 @@ namespace NzbDrone.Core.ThingiProvider
|
||||
TProviderDefinition Get(int id);
|
||||
TProviderDefinition Create(TProviderDefinition definition);
|
||||
void Update(TProviderDefinition definition);
|
||||
void Update(IEnumerable<TProviderDefinition> definitions);
|
||||
void Delete(int id);
|
||||
IEnumerable<TProviderDefinition> GetDefaultDefinitions();
|
||||
IEnumerable<TProviderDefinition> GetPresetDefinitions(TProviderDefinition providerDefinition);
|
||||
|
@@ -109,6 +109,11 @@ namespace NzbDrone.Core.ThingiProvider
|
||||
_eventAggregator.PublishEvent(new ProviderUpdatedEvent<TProvider>(definition));
|
||||
}
|
||||
|
||||
public virtual void Update(IEnumerable<TProviderDefinition> definitions)
|
||||
{
|
||||
_providerRepository.UpdateMany(definitions.ToList());
|
||||
}
|
||||
|
||||
public void Delete(int id)
|
||||
{
|
||||
_providerRepository.Delete(id);
|
||||
|
@@ -1,3 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Nancy;
|
||||
using NzbDrone.Core.Indexers;
|
||||
using NzbDrone.Core.Messaging.Commands;
|
||||
@@ -7,22 +9,68 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
{
|
||||
public class IndexerEditorModule : ProwlarrV1Module
|
||||
{
|
||||
private readonly IIndexerFactory _movieService;
|
||||
private readonly IIndexerFactory _indexerService;
|
||||
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")
|
||||
{
|
||||
_movieService = movieService;
|
||||
_indexerService = indexerService;
|
||||
_commandQueueManager = commandQueueManager;
|
||||
Put("/", movie => SaveAll());
|
||||
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()
|
||||
{
|
||||
var resource = Request.Body.FromJson<IndexerEditorResource>();
|
||||
|
||||
_movieService.DeleteIndexers(resource.IndexerIds);
|
||||
_indexerService.DeleteIndexers(resource.IndexerIds);
|
||||
|
||||
return new object();
|
||||
}
|
||||
|
@@ -5,5 +5,15 @@ namespace Prowlarr.Api.V1.Indexers
|
||||
public class IndexerEditorResource
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
public List<IndexerResource> ToResource(IEnumerable<IndexerDefinition> models)
|
||||
{
|
||||
return models.Select(ToResource).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user