import React, { useState, useEffect } from "react"; import { Form, Button, ListGroup } from "react-bootstrap"; import { Modal, Icon } from "src/components/Shared"; import { FormattedMessage, useIntl } from "react-intl"; import * as GQL from "src/core/generated-graphql"; import { IScraperSource } from "./constants"; import { OptionsEditor } from "./Options"; import { faCog, faGripVertical, faMinus, faPencilAlt, faPlus, } from "@fortawesome/free-solid-svg-icons"; interface ISourceEditor { isNew: boolean; availableSources: IScraperSource[]; source: IScraperSource; saveSource: (s?: IScraperSource) => void; defaultOptions: GQL.IdentifyMetadataOptionsInput; } export const SourcesEditor: React.FC = ({ isNew, availableSources, source: initialSource, saveSource, defaultOptions, }) => { const [source, setSource] = useState(initialSource); const [editingField, setEditingField] = useState(false); const intl = useIntl(); // if id is empty, then we are adding a new source const headerMsgId = isNew ? "actions.add" : "dialogs.edit_entity_title"; const acceptMsgId = isNew ? "actions.add" : "actions.confirm"; function handleSourceSelect(e: React.ChangeEvent) { const selectedSource = availableSources.find( (s) => s.id === e.currentTarget.value ); if (!selectedSource) return; setSource({ ...source, id: selectedSource.id, displayName: selectedSource.displayName, scraper_id: selectedSource.scraper_id, stash_box_endpoint: selectedSource.stash_box_endpoint, }); } return ( saveSource(source), text: intl.formatMessage({ id: acceptMsgId }), }} cancel={{ onClick: () => saveSource(), text: intl.formatMessage({ id: "actions.cancel" }), variant: "secondary", }} disabled={ (!source.scraper_id && !source.stash_box_endpoint) || editingField } >
{isNew && (
{availableSources.map((i) => ( ))}
)} setSource({ ...source, options: o })} source={source} setEditingField={(v) => setEditingField(v)} defaultOptions={defaultOptions} />
); }; interface ISourcesList { sources: IScraperSource[]; setSources: (s: IScraperSource[]) => void; editSource: (s?: IScraperSource) => void; canAdd: boolean; } export const SourcesList: React.FC = ({ sources, setSources, editSource, canAdd, }) => { const [tempSources, setTempSources] = useState(sources); const [dragIndex, setDragIndex] = useState(); const [mouseOverIndex, setMouseOverIndex] = useState(); useEffect(() => { setTempSources([...sources]); }, [sources]); function removeSource(index: number) { const newSources = [...sources]; newSources.splice(index, 1); setSources(newSources); } function onDragStart(event: React.DragEvent, index: number) { event.dataTransfer.effectAllowed = "move"; setDragIndex(index); } function onDragOver(event: React.DragEvent, index?: number) { if (dragIndex !== undefined && index !== undefined && index !== dragIndex) { const newSources = [...tempSources]; const moved = newSources.splice(dragIndex, 1); newSources.splice(index, 0, moved[0]); setTempSources(newSources); setDragIndex(index); } event.dataTransfer.dropEffect = "move"; event.preventDefault(); } function onDragOverDefault(event: React.DragEvent) { event.dataTransfer.dropEffect = "move"; event.preventDefault(); } function onDrop() { // assume we've already set the temp source list // feed it up setSources(tempSources); setDragIndex(undefined); setMouseOverIndex(undefined); } return (
{tempSources.map((s, index) => ( onDragStart(e, index)} onDragEnter={(e) => onDragOver(e, index)} onDrop={() => onDrop()} >
setMouseOverIndex(index)} onMouseLeave={() => setMouseOverIndex(undefined)} >
{s.displayName}
))}
{canAdd && (
)}
); };