Feature: Deluge download client (#12)

* chore: add go-libdeluge package

* feat: implement deluge v1 and v2 clients

* feat(web): handle add and update deluge clients

* chore: temp remove releaseinfo parser
This commit is contained in:
Ludvig Lundgren 2021-08-20 22:08:32 +02:00 committed by GitHub
parent eb5b040eeb
commit 0c4aaa29b0
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
19 changed files with 493 additions and 122 deletions

View file

@ -10,19 +10,7 @@ import {TextField} from "./inputs";
import DEBUG from "./debug";
import APIClient from "../api/APIClient";
import {queryClient} from "../App";
interface radioFieldsetOption {
label: string;
value: string;
}
const actionTypeOptions: radioFieldsetOption[] = [
{label: "Test", value: "TEST"},
{label: "Watch dir", value: "WATCH_FOLDER"},
{label: "Exec", value: "EXEC"},
{label: "qBittorrent", value: "QBITTORRENT"},
{label: "Deluge", value: "DELUGE"},
];
import {ActionTypeNameMap, ActionTypeOptions, DownloadClientTypeNameMap} from "../domain/constants";
interface FilterListProps {
actions: Action[];
@ -262,7 +250,8 @@ function ListItem({action, clients, filterID, idx}: ListItemProps) {
</div>
</div>
)
case "DELUGE":
case "DELUGE_V1":
case "DELUGE_V2":
return (
<div>
<div className="mt-6 grid grid-cols-12 gap-6">
@ -426,7 +415,7 @@ function ListItem({action, clients, filterID, idx}: ListItemProps) {
</div>
<div className="mt-4 flex-shrink-0 sm:mt-0 sm:ml-5">
<div className="flex overflow-hidden -space-x-1">
<span className="text-sm font-normal text-gray-500">{action.type}</span>
<span className="text-sm font-normal text-gray-500">{ActionTypeNameMap[action.type]}</span>
</div>
</div>
</div>
@ -561,7 +550,7 @@ function ListItem({action, clients, filterID, idx}: ListItemProps) {
<Listbox.Button
className="bg-white relative w-full border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<span
className="block truncate">{input.value ? actionTypeOptions.find(c => c.value === input.value)!.label : "Choose a type"}</span>
className="block truncate">{input.value ? ActionTypeOptions.find(c => c.value === input.value)!.label : "Choose a type"}</span>
<span
className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>
@ -579,7 +568,7 @@ function ListItem({action, clients, filterID, idx}: ListItemProps) {
static
className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
>
{actionTypeOptions.map((opt) => (
{ActionTypeOptions.map((opt) => (
<Listbox.Option
key={opt.value}
className={({active}) =>

View file

@ -0,0 +1,97 @@
import {Field} from "react-final-form";
import {Listbox, Transition} from "@headlessui/react";
import {CheckIcon, SelectorIcon} from "@heroicons/react/solid";
import React, {Fragment} from "react";
import {classNames} from "../../styles/utils";
interface SelectOption {
label: string;
value: string;
}
interface props {
name: string;
label: string;
optionDefaultText: string;
options: SelectOption[];
}
function SelectField({name, label, optionDefaultText, options}: props) {
return (
<div className="col-span-6 sm:col-span-6">
<Field
name={name}
type="select"
render={({input}) => (
<Listbox value={input.value} onChange={input.onChange}>
{({open}) => (
<div
className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
<Listbox.Label
className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2">{label}</Listbox.Label>
<div className="mt-2 relative">
<Listbox.Button
className="bg-white relative w-full border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">
<span
className="block truncate">{input.value ? options.find(c => c.value === input.value)!.label : optionDefaultText}</span>
<span
className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">
<SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>
</span>
</Listbox.Button>
<Transition
show={open}
as={Fragment}
leave="transition ease-in duration-100"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Listbox.Options
static
className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"
>
{options.map((opt) => (
<Listbox.Option
key={opt.value}
className={({active}) =>
classNames(
active ? 'text-white bg-indigo-600' : 'text-gray-900',
'cursor-default select-none relative py-2 pl-3 pr-9'
)
}
value={opt.value}
>
{({selected, active}) => (
<>
<span className={classNames(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>
{opt.label}
</span>
{selected ? (
<span
className={classNames(
active ? 'text-white' : 'text-indigo-600',
'absolute inset-y-0 right-0 flex items-center pr-4'
)}
>
<CheckIcon className="h-5 w-5" aria-hidden="true"/>
</span>
) : null}
</>
)}
</Listbox.Option>
))}
</Listbox.Options>
</Transition>
</div>
</div>
)}
</Listbox>
)}/>
</div>
)
}
export default SelectField;

View file

@ -5,3 +5,4 @@ export { default as TextAreaWide } from "./TextAreaWide";
export { default as MultiSelectField } from "./MultiSelectField";
export { default as RadioFieldset } from "./RadioFieldset";
export { default as SwitchGroup } from "./SwitchGroup";
export { default as SelectField } from "./SelectField";