mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
fix(indexes): toggle on and off with switch (#1164)
* chore(indexers): replace array position with id * fix(indexers): enable and disable without editing * feat(indexer): add toggle endpoint and refactoring --------- Co-authored-by: ze0s <ze0s@riseup.net>
This commit is contained in:
parent
603191b47d
commit
8600d3a2ab
7 changed files with 167 additions and 50 deletions
|
@ -232,3 +232,25 @@ func (r *IndexerRepo) Delete(ctx context.Context, id int) error {
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (r *IndexerRepo) ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error {
|
||||||
|
var err error
|
||||||
|
|
||||||
|
queryBuilder := r.db.squirrel.
|
||||||
|
Update("indexer").
|
||||||
|
Set("enabled", enabled).
|
||||||
|
Set("updated_at", sq.Expr("CURRENT_TIMESTAMP")).
|
||||||
|
Where(sq.Eq{"id": indexerID})
|
||||||
|
|
||||||
|
query, args, err := queryBuilder.ToSql()
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error building query")
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = r.db.handler.ExecContext(ctx, query, args...)
|
||||||
|
if err != nil {
|
||||||
|
return errors.Wrap(err, "error executing query")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ type IndexerRepo interface {
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
FindByFilterID(ctx context.Context, id int) ([]Indexer, error)
|
FindByFilterID(ctx context.Context, id int) ([]Indexer, error)
|
||||||
FindByID(ctx context.Context, id int) (*Indexer, error)
|
FindByID(ctx context.Context, id int) (*Indexer, error)
|
||||||
|
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type Indexer struct {
|
type Indexer struct {
|
||||||
|
|
|
@ -22,6 +22,7 @@ type indexerService interface {
|
||||||
GetTemplates() ([]domain.IndexerDefinition, error)
|
GetTemplates() ([]domain.IndexerDefinition, error)
|
||||||
Delete(ctx context.Context, id int) error
|
Delete(ctx context.Context, id int) error
|
||||||
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
|
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
|
||||||
|
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type indexerHandler struct {
|
type indexerHandler struct {
|
||||||
|
@ -41,13 +42,15 @@ func newIndexerHandler(encoder encoder, service indexerService, ircSvc ircServic
|
||||||
func (h indexerHandler) Routes(r chi.Router) {
|
func (h indexerHandler) Routes(r chi.Router) {
|
||||||
r.Get("/schema", h.getSchema)
|
r.Get("/schema", h.getSchema)
|
||||||
r.Post("/", h.store)
|
r.Post("/", h.store)
|
||||||
r.Put("/", h.update)
|
|
||||||
r.Get("/", h.getAll)
|
r.Get("/", h.getAll)
|
||||||
r.Get("/options", h.list)
|
r.Get("/options", h.list)
|
||||||
|
|
||||||
r.Route("/{indexerID}", func(r chi.Router) {
|
r.Route("/{indexerID}", func(r chi.Router) {
|
||||||
|
r.Put("/", h.update)
|
||||||
r.Delete("/", h.delete)
|
r.Delete("/", h.delete)
|
||||||
r.Post("/api/test", h.testApi)
|
r.Post("/api/test", h.testApi)
|
||||||
|
|
||||||
|
r.Patch("/enabled", h.toggleEnabled)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -178,3 +181,31 @@ func (h indexerHandler) testApi(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
h.encoder.StatusResponse(w, http.StatusOK, res)
|
h.encoder.StatusResponse(w, http.StatusOK, res)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (h indexerHandler) toggleEnabled(w http.ResponseWriter, r *http.Request) {
|
||||||
|
var (
|
||||||
|
ctx = r.Context()
|
||||||
|
indexerID = chi.URLParam(r, "indexerID")
|
||||||
|
data struct {
|
||||||
|
Enabled bool `json:"enabled"`
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
id, err := strconv.Atoi(indexerID)
|
||||||
|
if err != nil {
|
||||||
|
h.encoder.Error(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(r.Body).Decode(&data); err != nil {
|
||||||
|
h.encoder.Error(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := h.service.ToggleEnabled(ctx, id, data.Enabled); err != nil {
|
||||||
|
h.encoder.Error(w, err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
h.encoder.NoContent(w)
|
||||||
|
}
|
||||||
|
|
|
@ -36,6 +36,7 @@ type Service interface {
|
||||||
GetTorznabIndexers() []domain.IndexerDefinition
|
GetTorznabIndexers() []domain.IndexerDefinition
|
||||||
Start() error
|
Start() error
|
||||||
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
|
TestApi(ctx context.Context, req domain.IndexerTestApiRequest) error
|
||||||
|
ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error
|
||||||
}
|
}
|
||||||
|
|
||||||
type service struct {
|
type service struct {
|
||||||
|
@ -77,8 +78,7 @@ func NewService(log logger.Logger, config *domain.Config, repo domain.IndexerRep
|
||||||
|
|
||||||
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
func (s *service) Store(ctx context.Context, indexer domain.Indexer) (*domain.Indexer, error) {
|
||||||
// if indexer is rss or torznab do additional cleanup for identifier
|
// if indexer is rss or torznab do additional cleanup for identifier
|
||||||
switch indexer.Implementation {
|
if isImplFeed(indexer.Implementation) {
|
||||||
case "torznab", "newznab", "rss":
|
|
||||||
// make lowercase
|
// make lowercase
|
||||||
cleanName := strings.ToLower(indexer.Name)
|
cleanName := strings.ToLower(indexer.Name)
|
||||||
|
|
||||||
|
@ -114,7 +114,7 @@ func (s *service) Update(ctx context.Context, indexer domain.Indexer) (*domain.I
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
if indexer.Implementation == "torznab" || indexer.Implementation == "rss" {
|
if isImplFeed(indexer.Implementation) {
|
||||||
if !indexer.Enabled {
|
if !indexer.Enabled {
|
||||||
s.stopFeed(indexer.Identifier)
|
s.stopFeed(indexer.Identifier)
|
||||||
}
|
}
|
||||||
|
@ -220,12 +220,9 @@ func (s *service) mapIndexers() (map[string]*domain.IndexerDefinition, error) {
|
||||||
|
|
||||||
func (s *service) mapIndexer(indexer domain.Indexer) (*domain.IndexerDefinition, error) {
|
func (s *service) mapIndexer(indexer domain.Indexer) (*domain.IndexerDefinition, error) {
|
||||||
definitionName := indexer.Identifier
|
definitionName := indexer.Identifier
|
||||||
if indexer.Implementation == "torznab" {
|
|
||||||
definitionName = "torznab"
|
if isImplFeed(indexer.Implementation) {
|
||||||
} else if indexer.Implementation == "newznab" {
|
definitionName = indexer.Implementation
|
||||||
definitionName = "newznab"
|
|
||||||
} else if indexer.Implementation == "rss" {
|
|
||||||
definitionName = "rss"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
d := s.getDefinitionByName(definitionName)
|
d := s.getDefinitionByName(definitionName)
|
||||||
|
@ -332,7 +329,8 @@ func (s *service) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, indexer := range indexerDefinitions {
|
for _, indexer := range indexerDefinitions {
|
||||||
if indexer.IRC != nil {
|
switch indexer.Implementation {
|
||||||
|
case string(domain.IndexerImplementationIRC):
|
||||||
// add to irc server lookup table
|
// add to irc server lookup table
|
||||||
s.mapIRCServerDefinitionLookup(indexer.IRC.Server, indexer)
|
s.mapIRCServerDefinitionLookup(indexer.IRC.Server, indexer)
|
||||||
|
|
||||||
|
@ -342,15 +340,16 @@ func (s *service) Start() error {
|
||||||
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// handle Torznab
|
// handle feeds
|
||||||
if indexer.Implementation == "torznab" {
|
case string(domain.IndexerImplementationRSS):
|
||||||
s.torznabIndexers[indexer.Identifier] = indexer
|
|
||||||
} else if indexer.Implementation == "newznab" {
|
|
||||||
s.newznabIndexers[indexer.Identifier] = indexer
|
|
||||||
} else if indexer.Implementation == "rss" {
|
|
||||||
s.rssIndexers[indexer.Identifier] = indexer
|
s.rssIndexers[indexer.Identifier] = indexer
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationTorznab):
|
||||||
|
s.torznabIndexers[indexer.Identifier] = indexer
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationNewznab):
|
||||||
|
s.newznabIndexers[indexer.Identifier] = indexer
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -360,13 +359,16 @@ func (s *service) Start() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *service) removeIndexer(indexer domain.Indexer) {
|
func (s *service) removeIndexer(indexer domain.Indexer) {
|
||||||
// remove Torznab
|
// handle feeds
|
||||||
if indexer.Implementation == "torznab" {
|
switch indexer.Implementation {
|
||||||
delete(s.torznabIndexers, indexer.Identifier)
|
case string(domain.IndexerImplementationRSS):
|
||||||
} else if indexer.Implementation == "newznab" {
|
|
||||||
delete(s.newznabIndexers, indexer.Identifier)
|
|
||||||
} else if indexer.Implementation == "rss" {
|
|
||||||
delete(s.rssIndexers, indexer.Identifier)
|
delete(s.rssIndexers, indexer.Identifier)
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationTorznab):
|
||||||
|
delete(s.torznabIndexers, indexer.Identifier)
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationNewznab):
|
||||||
|
delete(s.newznabIndexers, indexer.Identifier)
|
||||||
}
|
}
|
||||||
|
|
||||||
// remove mapped definition
|
// remove mapped definition
|
||||||
|
@ -383,7 +385,8 @@ func (s *service) addIndexer(indexer domain.Indexer) error {
|
||||||
return errors.New("addindexer: could not find definition")
|
return errors.New("addindexer: could not find definition")
|
||||||
}
|
}
|
||||||
|
|
||||||
if indexerDefinition.IRC != nil {
|
switch indexer.Implementation {
|
||||||
|
case string(domain.IndexerImplementationIRC):
|
||||||
// add to irc server lookup table
|
// add to irc server lookup table
|
||||||
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
|
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
|
||||||
|
|
||||||
|
@ -393,15 +396,16 @@ func (s *service) addIndexer(indexer domain.Indexer) error {
|
||||||
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// handle Torznab and RSS
|
// handle feeds
|
||||||
if indexerDefinition.Implementation == "torznab" {
|
case string(domain.IndexerImplementationRSS):
|
||||||
s.torznabIndexers[indexer.Identifier] = indexerDefinition
|
|
||||||
} else if indexer.Implementation == "newznab" {
|
|
||||||
s.newznabIndexers[indexer.Identifier] = indexerDefinition
|
|
||||||
} else if indexerDefinition.Implementation == "rss" {
|
|
||||||
s.rssIndexers[indexer.Identifier] = indexerDefinition
|
s.rssIndexers[indexer.Identifier] = indexerDefinition
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationTorznab):
|
||||||
|
s.torznabIndexers[indexer.Identifier] = indexerDefinition
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationNewznab):
|
||||||
|
s.newznabIndexers[indexer.Identifier] = indexerDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
|
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
|
||||||
|
@ -419,7 +423,8 @@ func (s *service) updateIndexer(indexer domain.Indexer) error {
|
||||||
return errors.New("update indexer: could not find definition")
|
return errors.New("update indexer: could not find definition")
|
||||||
}
|
}
|
||||||
|
|
||||||
if indexerDefinition.IRC != nil {
|
switch indexer.Implementation {
|
||||||
|
case string(domain.IndexerImplementationIRC):
|
||||||
// add to irc server lookup table
|
// add to irc server lookup table
|
||||||
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
|
s.mapIRCServerDefinitionLookup(indexerDefinition.IRC.Server, indexerDefinition)
|
||||||
|
|
||||||
|
@ -429,15 +434,16 @@ func (s *service) updateIndexer(indexer domain.Indexer) error {
|
||||||
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
s.log.Error().Stack().Err(err).Msgf("indexer.start: could not init api client for: '%s'", indexer.Identifier)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
// handle Torznab
|
// handle feeds
|
||||||
if indexerDefinition.Implementation == "torznab" {
|
case string(domain.IndexerImplementationRSS):
|
||||||
s.torznabIndexers[indexer.Identifier] = indexerDefinition
|
|
||||||
} else if indexer.Implementation == "newznab" {
|
|
||||||
s.newznabIndexers[indexer.Identifier] = indexerDefinition
|
|
||||||
} else if indexerDefinition.Implementation == "rss" {
|
|
||||||
s.rssIndexers[indexer.Identifier] = indexerDefinition
|
s.rssIndexers[indexer.Identifier] = indexerDefinition
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationTorznab):
|
||||||
|
s.torznabIndexers[indexer.Identifier] = indexerDefinition
|
||||||
|
|
||||||
|
case string(domain.IndexerImplementationNewznab):
|
||||||
|
s.newznabIndexers[indexer.Identifier] = indexerDefinition
|
||||||
}
|
}
|
||||||
|
|
||||||
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
|
s.mappedDefinitions[indexer.Identifier] = indexerDefinition
|
||||||
|
@ -672,3 +678,40 @@ func (s *service) TestApi(ctx context.Context, req domain.IndexerTestApiRequest)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *service) ToggleEnabled(ctx context.Context, indexerID int, enabled bool) error {
|
||||||
|
indexer, err := s.FindByID(ctx, indexerID)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := s.repo.ToggleEnabled(ctx, int(indexer.ID), enabled); err != nil {
|
||||||
|
s.log.Error().Err(err).Msg("could not update indexer enabled")
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// update indexerInstances
|
||||||
|
if err := s.updateIndexer(*indexer); err != nil {
|
||||||
|
s.log.Error().Err(err).Msgf("failed to add indexer: %s", indexer.Name)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
if isImplFeed(indexer.Implementation) {
|
||||||
|
if !indexer.Enabled {
|
||||||
|
s.stopFeed(indexer.Identifier)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
s.log.Debug().Msgf("indexer.toggle_enabled: update indexer '%d' to '%v'", indexerID, enabled)
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func isImplFeed(implementation string) bool {
|
||||||
|
switch implementation {
|
||||||
|
case "torznab", "newznab", "rss":
|
||||||
|
return true
|
||||||
|
default:
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -240,13 +240,16 @@ export const APIClient = {
|
||||||
create: (indexer: Indexer) => appClient.Post<Indexer>("api/indexer", {
|
create: (indexer: Indexer) => appClient.Post<Indexer>("api/indexer", {
|
||||||
body: indexer
|
body: indexer
|
||||||
}),
|
}),
|
||||||
update: (indexer: Indexer) => appClient.Put("api/indexer", {
|
update: (indexer: Indexer) => appClient.Put(`api/indexer/${indexer.id}`, {
|
||||||
body: indexer
|
body: indexer
|
||||||
}),
|
}),
|
||||||
delete: (id: number) => appClient.Delete(`api/indexer/${id}`),
|
delete: (id: number) => appClient.Delete(`api/indexer/${id}`),
|
||||||
testApi: (req: IndexerTestApiReq) => appClient.Post<IndexerTestApiReq>(`api/indexer/${req.id}/api/test`, {
|
testApi: (req: IndexerTestApiReq) => appClient.Post<IndexerTestApiReq>(`api/indexer/${req.id}/api/test`, {
|
||||||
body: req
|
body: req
|
||||||
})
|
}),
|
||||||
|
toggleEnable: (id: number, enabled: boolean) => appClient.Patch(`api/indexer/${id}/enabled`, {
|
||||||
|
body: { enabled }
|
||||||
|
}),
|
||||||
},
|
},
|
||||||
irc: {
|
irc: {
|
||||||
getNetworks: () => appClient.Get<IrcNetworkWithHealth[]>("api/irc"),
|
getNetworks: () => appClient.Get<IrcNetworkWithHealth[]>("api/irc"),
|
||||||
|
|
|
@ -4,9 +4,11 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { useState, useMemo } from "react";
|
import { useState, useMemo } from "react";
|
||||||
import { useQuery } from "@tanstack/react-query";
|
import toast from "react-hot-toast";
|
||||||
|
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||||
import { Switch } from "@headlessui/react";
|
import { Switch } from "@headlessui/react";
|
||||||
|
|
||||||
|
import Toast from "@components/notifications/Toast";
|
||||||
import { IndexerAddForm, IndexerUpdateForm } from "@forms";
|
import { IndexerAddForm, IndexerUpdateForm } from "@forms";
|
||||||
import { useToggle } from "@hooks/hooks";
|
import { useToggle } from "@hooks/hooks";
|
||||||
import { classNames } from "@utils";
|
import { classNames } from "@utils";
|
||||||
|
@ -114,8 +116,23 @@ interface ListItemProps {
|
||||||
const ListItem = ({ indexer }: ListItemProps) => {
|
const ListItem = ({ indexer }: ListItemProps) => {
|
||||||
const [updateIsOpen, toggleUpdate] = useToggle(false);
|
const [updateIsOpen, toggleUpdate] = useToggle(false);
|
||||||
|
|
||||||
|
const queryClient = useQueryClient();
|
||||||
|
|
||||||
|
const updateMutation = useMutation({
|
||||||
|
mutationFn: (enabled: boolean) => APIClient.indexers.toggleEnable(indexer.id, enabled),
|
||||||
|
onSuccess: () => {
|
||||||
|
queryClient.invalidateQueries({ queryKey: indexerKeys.lists() });
|
||||||
|
toast.custom((t) => <Toast type="success" body={`${indexer.name} was updated successfully`} t={t} />);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
const onToggleMutation = (newState: boolean) => {
|
||||||
|
// backend is rejecting when ending the whole object
|
||||||
|
updateMutation.mutate(newState);
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li key={indexer.name}>
|
<li>
|
||||||
<div className="grid grid-cols-12 items-center py-1.5">
|
<div className="grid grid-cols-12 items-center py-1.5">
|
||||||
<IndexerUpdateForm
|
<IndexerUpdateForm
|
||||||
isOpen={updateIsOpen}
|
isOpen={updateIsOpen}
|
||||||
|
@ -124,8 +141,9 @@ const ListItem = ({ indexer }: ListItemProps) => {
|
||||||
/>
|
/>
|
||||||
<div className="col-span-2 sm:col-span-1 flex px-6 items-center sm:px-6">
|
<div className="col-span-2 sm:col-span-1 flex px-6 items-center sm:px-6">
|
||||||
<Switch
|
<Switch
|
||||||
|
onClick={(e) => e.stopPropagation()}
|
||||||
checked={indexer.enabled ?? false}
|
checked={indexer.enabled ?? false}
|
||||||
onChange={toggleUpdate}
|
onChange={onToggleMutation}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
indexer.enabled ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
indexer.enabled ? "bg-blue-500" : "bg-gray-200 dark:bg-gray-600",
|
||||||
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
"relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500"
|
||||||
|
@ -225,8 +243,8 @@ function IndexerSettings() {
|
||||||
Implementation <span className="sort-indicator">{sortedIndexers.getSortIndicator("implementation")}</span>
|
Implementation <span className="sort-indicator">{sortedIndexers.getSortIndicator("implementation")}</span>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{sortedIndexers.items.map((indexer, idx) => (
|
{sortedIndexers.items.map((indexer) => (
|
||||||
<ListItem indexer={indexer} key={idx} />
|
<ListItem indexer={indexer} key={indexer.id} />
|
||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
|
|
|
@ -263,7 +263,7 @@ const ListItem = ({ network, expanded }: ListItemProps) => {
|
||||||
/>
|
/>
|
||||||
<div className="col-span-2 md:col-span-1 flex pl-5 text-gray-500 dark:text-gray-400">
|
<div className="col-span-2 md:col-span-1 flex pl-5 text-gray-500 dark:text-gray-400">
|
||||||
<Switch
|
<Switch
|
||||||
onClick={(e: MouseEvent) => e.stopPropagation()}
|
onClick={(e) => e.stopPropagation()}
|
||||||
checked={network.enabled}
|
checked={network.enabled}
|
||||||
onChange={onToggleMutation}
|
onChange={onToggleMutation}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
@ -787,4 +787,3 @@ const IRCLogsDropdown = () => {
|
||||||
</Menu>
|
</Menu>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue