mirror of
https://github.com/idanoo/autobrr
synced 2025-07-22 16:29:12 +00:00
refactor(web): rename custom components (#1581)
Co-authored-by: ze0s <43699394+zze0s@users.noreply.github.com>
This commit is contained in:
parent
7d7bf9ed4c
commit
e8e45c664d
17 changed files with 459 additions and 430 deletions
|
@ -13,7 +13,7 @@ interface ButtonProps {
|
|||
onClick?: () => void;
|
||||
}
|
||||
|
||||
export const Button = ({ children, className, disabled, onClick }: ButtonProps) => (
|
||||
export const TableButton = ({ children, className, disabled, onClick }: ButtonProps) => (
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(
|
||||
|
@ -27,7 +27,7 @@ export const Button = ({ children, className, disabled, onClick }: ButtonProps)
|
|||
</button>
|
||||
);
|
||||
|
||||
export const PageButton = ({ children, className, disabled, onClick }: ButtonProps) => (
|
||||
export const TablePageButton = ({ children, className, disabled, onClick }: ButtonProps) => (
|
||||
<button
|
||||
type="button"
|
||||
className={classNames(
|
||||
|
|
|
@ -3,5 +3,5 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
export { Button, PageButton } from "./Buttons";
|
||||
export { TableButton, TablePageButton } from "./Buttons";
|
||||
export { AgeCell, IndexerCell, NameCell, TitleCell, ReleaseStatusCell, LinksCell } from "./Cells";
|
||||
|
|
|
@ -13,10 +13,18 @@ import { useToggle } from "@hooks/hooks";
|
|||
import { EyeIcon, EyeSlashIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
import { SelectFieldProps } from "./select";
|
||||
import * as common from "./common";
|
||||
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
import { Checkbox } from "@components/Checkbox";
|
||||
import {
|
||||
DropdownIndicator,
|
||||
ErrorField, IndicatorSeparator,
|
||||
RequiredField,
|
||||
SelectControl,
|
||||
SelectInput,
|
||||
SelectMenu,
|
||||
SelectOption
|
||||
} from "@components/inputs/common.tsx";
|
||||
|
||||
interface TextFieldWideProps {
|
||||
name: string;
|
||||
|
@ -50,7 +58,7 @@ export const TextFieldWide = ({
|
|||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<common.RequiredField required={required} />
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -85,7 +93,7 @@ export const TextFieldWide = ({
|
|||
{help && (
|
||||
<p className="mt-2 text-sm text-gray-500" id={`${name}-description`}>{help}</p>
|
||||
)}
|
||||
<common.ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
<ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -125,7 +133,7 @@ export const PasswordFieldWide = ({
|
|||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<common.RequiredField required={required} />
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -163,7 +171,7 @@ export const PasswordFieldWide = ({
|
|||
{help && (
|
||||
<p className="mt-2 text-sm text-gray-500" id={`${name}-description`}>{help}</p>
|
||||
)}
|
||||
<common.ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
<ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -198,7 +206,7 @@ export const NumberFieldWide = ({
|
|||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<common.RequiredField required={required} />
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -233,7 +241,7 @@ export const NumberFieldWide = ({
|
|||
{help && (
|
||||
<p className="mt-2 text-sm text-gray-500 dark:text-gray-500" id={`${name}-description`}>{help}</p>
|
||||
)}
|
||||
<common.ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
<ErrorField name={name} classNames="block text-red-500 mt-2" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
@ -325,12 +333,12 @@ export const SelectFieldWide = ({
|
|||
isClearable={true}
|
||||
isSearchable={true}
|
||||
components={{
|
||||
Input: common.SelectInput,
|
||||
Control: common.SelectControl,
|
||||
Menu: common.SelectMenu,
|
||||
Option: common.SelectOption,
|
||||
IndicatorSeparator: common.IndicatorSeparator,
|
||||
DropdownIndicator: common.DropdownIndicator
|
||||
Input: SelectInput,
|
||||
Control: SelectControl,
|
||||
Menu: SelectMenu,
|
||||
Option: SelectOption,
|
||||
IndicatorSeparator: IndicatorSeparator,
|
||||
DropdownIndicator: DropdownIndicator
|
||||
}}
|
||||
placeholder={optionDefaultText}
|
||||
styles={{
|
||||
|
|
|
@ -23,9 +23,17 @@ import Toast from "@components/notifications/Toast";
|
|||
import { Checkbox } from "@components/Checkbox";
|
||||
import { TitleSubtitle } from "@components/headings";
|
||||
|
||||
import * as FilterSection from "./_components";
|
||||
import * as FilterActions from "./action_components";
|
||||
import { DownloadClientsQueryOptions } from "@api/queries";
|
||||
import { FilterHalfRow, FilterLayout, FilterPage, FilterSection } from "@screens/filters/sections/_components.tsx";
|
||||
import {
|
||||
Arr,
|
||||
Deluge, Exec,
|
||||
Porla,
|
||||
QBittorrent,
|
||||
RTorrent,
|
||||
SABnzbd, Test,
|
||||
Transmission, WatchFolder, WebHook
|
||||
} from "@screens/filters/sections/action_components";
|
||||
|
||||
// interface FilterActionsProps {
|
||||
// filter: Filter;
|
||||
|
@ -141,35 +149,35 @@ const TypeForm = (props: ClientActionProps) => {
|
|||
switch (action.type) {
|
||||
// torrent clients
|
||||
case "QBITTORRENT":
|
||||
return <FilterActions.QBittorrent {...props} />;
|
||||
return <QBittorrent {...props} />;
|
||||
case "DELUGE_V1":
|
||||
case "DELUGE_V2":
|
||||
return <FilterActions.Deluge {...props} />;
|
||||
return <Deluge {...props} />;
|
||||
case "RTORRENT":
|
||||
return <FilterActions.RTorrent {...props} />;
|
||||
return <RTorrent {...props} />;
|
||||
case "TRANSMISSION":
|
||||
return <FilterActions.Transmission {...props} />;
|
||||
return <Transmission {...props} />;
|
||||
case "PORLA":
|
||||
return <FilterActions.Porla {...props} />;
|
||||
return <Porla {...props} />;
|
||||
// arrs
|
||||
case "RADARR":
|
||||
case "SONARR":
|
||||
case "LIDARR":
|
||||
case "WHISPARR":
|
||||
case "READARR":
|
||||
return <FilterActions.Arr {...props} />;
|
||||
return <Arr {...props} />;
|
||||
// nzb
|
||||
case "SABNZBD":
|
||||
return <FilterActions.SABnzbd {...props} />;
|
||||
return <SABnzbd {...props} />;
|
||||
// autobrr actions
|
||||
case "TEST":
|
||||
return <FilterActions.Test />;
|
||||
return <Test />;
|
||||
case "EXEC":
|
||||
return <FilterActions.Exec {...props} />;
|
||||
return <Exec {...props} />;
|
||||
case "WATCH_FOLDER":
|
||||
return <FilterActions.WatchFolder {...props} />;
|
||||
return <WatchFolder {...props} />;
|
||||
case "WEBHOOK":
|
||||
return <FilterActions.WebHook {...props} />;
|
||||
return <WebHook {...props} />;
|
||||
default:
|
||||
// TODO(stacksmash76): Indicate error
|
||||
return null;
|
||||
|
@ -268,13 +276,13 @@ function FilterActionsItem({ action, clients, idx, initialEdit, remove }: Filter
|
|||
text="Are you sure you want to remove this action? This action cannot be undone."
|
||||
/>
|
||||
|
||||
<FilterSection.Page gap="sm:gap-y-6">
|
||||
<FilterSection.Section
|
||||
<FilterPage gap="sm:gap-y-6">
|
||||
<FilterSection
|
||||
title="Action"
|
||||
subtitle="Define the download client for your action and its name"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<Select
|
||||
name={`actions.${idx}.type`}
|
||||
label="Action type"
|
||||
|
@ -282,13 +290,13 @@ function FilterActionsItem({ action, clients, idx, initialEdit, remove }: Filter
|
|||
options={ActionTypeOptions}
|
||||
tooltip={<div><p>Select the action type for this action.</p></div>}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<FilterSection.HalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField name={`actions.${idx}.name`} label="Name" />
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<TypeForm action={action} clients={clients} idx={idx} />
|
||||
|
||||
|
@ -309,7 +317,7 @@ function FilterActionsItem({ action, clients, idx, initialEdit, remove }: Filter
|
|||
Close
|
||||
</button>
|
||||
</div>
|
||||
</FilterSection.Page>
|
||||
</FilterPage>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
|
|
|
@ -7,14 +7,25 @@ import { useFormikContext } from "formik";
|
|||
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
import { WarningAlert } from "@components/alerts";
|
||||
|
||||
import * as Input from "@components/inputs";
|
||||
import * as CONSTS from "@domain/constants";
|
||||
|
||||
import { CollapsibleSection } from "./_components";
|
||||
import * as Components from "./_components";
|
||||
import {
|
||||
CollapsibleSection,
|
||||
FilterHalfRow,
|
||||
FilterLayout,
|
||||
FilterLayoutClass,
|
||||
FilterTightGridGapClass
|
||||
} from "./_components";
|
||||
import { classNames } from "@utils";
|
||||
|
||||
import * as CONSTS from "@domain/constants";
|
||||
import {
|
||||
MultiSelect, NumberField, RegexField,
|
||||
RegexTextAreaField,
|
||||
Select,
|
||||
SwitchGroup,
|
||||
TextAreaAutoResize,
|
||||
TextField
|
||||
} from "@components/inputs";
|
||||
|
||||
// type ValueConsumer = {
|
||||
// values: FormikValues;
|
||||
// };
|
||||
|
@ -29,15 +40,15 @@ const Releases = () => {
|
|||
title="Release Names"
|
||||
subtitle="Match only certain release names and/or ignore other release names."
|
||||
>
|
||||
<Components.Layout>
|
||||
<Components.HalfRow>
|
||||
<Input.SwitchGroup name="use_regex" label="Use Regex" className="pt-2" />
|
||||
</Components.HalfRow>
|
||||
</Components.Layout>
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup name="use_regex" label="Use Regex" className="pt-2" />
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout>
|
||||
<Components.HalfRow>
|
||||
<Input.RegexTextAreaField
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<RegexTextAreaField
|
||||
name="match_releases"
|
||||
label="Match releases"
|
||||
useRegex={values.use_regex}
|
||||
|
@ -53,10 +64,10 @@ const Releases = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<Components.HalfRow>
|
||||
<Input.RegexTextAreaField
|
||||
<FilterHalfRow>
|
||||
<RegexTextAreaField
|
||||
name="except_releases"
|
||||
label="Except releases"
|
||||
useRegex={values.use_regex}
|
||||
|
@ -72,9 +83,9 @@ const Releases = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
{values.match_releases ? (
|
||||
<WarningAlert
|
||||
|
@ -112,7 +123,7 @@ const Groups = () => {
|
|||
title="Groups"
|
||||
subtitle="Match only certain groups and/or ignore other groups."
|
||||
>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="match_release_groups"
|
||||
label="Match release groups"
|
||||
columns={6}
|
||||
|
@ -124,7 +135,7 @@ const Groups = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="except_release_groups"
|
||||
label="Except release groups"
|
||||
columns={6}
|
||||
|
@ -150,7 +161,7 @@ const Categories = () => {
|
|||
title="Categories"
|
||||
subtitle="Match or exclude categories (if announced)"
|
||||
>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="match_categories"
|
||||
label="Match categories"
|
||||
columns={6}
|
||||
|
@ -162,7 +173,7 @@ const Categories = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="except_categories"
|
||||
label="Except categories"
|
||||
columns={6}
|
||||
|
@ -188,8 +199,8 @@ const Tags = () => {
|
|||
title="Tags"
|
||||
subtitle="Match or exclude tags (if announced)"
|
||||
>
|
||||
<div className={classNames("sm:col-span-6", Components.LayoutClass, Components.TightGridGapClass)}>
|
||||
<Input.TextAreaAutoResize
|
||||
<div className={classNames("sm:col-span-6", FilterLayoutClass, FilterTightGridGapClass)}>
|
||||
<TextAreaAutoResize
|
||||
name="tags"
|
||||
label="Match tags"
|
||||
columns={8}
|
||||
|
@ -201,7 +212,7 @@ const Tags = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name="tags_match_logic"
|
||||
label="Match logic"
|
||||
columns={4}
|
||||
|
@ -215,8 +226,8 @@ const Tags = () => {
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
<div className={classNames("sm:col-span-6", Components.LayoutClass, Components.TightGridGapClass)}>
|
||||
<Input.TextAreaAutoResize
|
||||
<div className={classNames("sm:col-span-6", FilterLayoutClass, FilterTightGridGapClass)}>
|
||||
<TextAreaAutoResize
|
||||
name="except_tags"
|
||||
label="Except tags"
|
||||
columns={8}
|
||||
|
@ -228,7 +239,7 @@ const Tags = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name="except_tags_match_logic"
|
||||
label="Except logic"
|
||||
columns={4}
|
||||
|
@ -256,7 +267,7 @@ const Uploaders = () => {
|
|||
title="Uploaders"
|
||||
subtitle="Match or ignore uploaders (if announced)"
|
||||
>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="match_uploaders"
|
||||
label="Match uploaders"
|
||||
columns={6}
|
||||
|
@ -268,7 +279,7 @@ const Uploaders = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="except_uploaders"
|
||||
label="Except uploaders"
|
||||
columns={6}
|
||||
|
@ -295,13 +306,13 @@ const Language = () => {
|
|||
title="Language"
|
||||
subtitle="Match or ignore languages (if announced)"
|
||||
>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="match_language"
|
||||
options={CONSTS.LANGUAGE_OPTIONS}
|
||||
label="Match Language"
|
||||
columns={6}
|
||||
/>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="except_language"
|
||||
options={CONSTS.LANGUAGE_OPTIONS}
|
||||
label="Except Language"
|
||||
|
@ -321,13 +332,13 @@ const Origins = () => {
|
|||
title="Origins"
|
||||
subtitle="Match Internals, Scene, P2P, etc. (if announced)"
|
||||
>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="origins"
|
||||
options={CONSTS.ORIGIN_OPTIONS}
|
||||
label="Match Origins"
|
||||
columns={6}
|
||||
/>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="except_origins"
|
||||
options={CONSTS.ORIGIN_OPTIONS}
|
||||
label="Except Origins"
|
||||
|
@ -347,7 +358,7 @@ const Freeleech = () => {
|
|||
title="Freeleech"
|
||||
subtitle="Match based off freeleech (if announced)"
|
||||
>
|
||||
<Input.TextField
|
||||
<TextField
|
||||
name="freeleech_percent"
|
||||
label="Freeleech percent"
|
||||
disabled={values.freeleech}
|
||||
|
@ -368,8 +379,8 @@ const Freeleech = () => {
|
|||
columns={6}
|
||||
placeholder="eg. 50,75-100"
|
||||
/>
|
||||
<Components.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name="freeleech"
|
||||
label="Freeleech"
|
||||
className="py-0"
|
||||
|
@ -389,7 +400,7 @@ const Freeleech = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.HalfRow>
|
||||
</FilterHalfRow>
|
||||
</CollapsibleSection>
|
||||
);
|
||||
}
|
||||
|
@ -414,15 +425,15 @@ const FeedSpecific = () => {
|
|||
<>These options are <span className="font-bold">only</span> for Feeds such as RSS, Torznab and Newznab</>
|
||||
}
|
||||
>
|
||||
<Components.Layout>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout>
|
||||
<SwitchGroup
|
||||
name="use_regex_description"
|
||||
label="Use Regex"
|
||||
className="col-span-12 sm:col-span-6"
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Input.RegexTextAreaField
|
||||
<RegexTextAreaField
|
||||
name="match_description"
|
||||
label="Match description"
|
||||
useRegex={values.use_regex_description}
|
||||
|
@ -438,7 +449,7 @@ const FeedSpecific = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.RegexTextAreaField
|
||||
<RegexTextAreaField
|
||||
name="except_description"
|
||||
label="Except description"
|
||||
useRegex={values.use_regex_description}
|
||||
|
@ -454,7 +465,7 @@ const FeedSpecific = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="min_seeders"
|
||||
label="Min Seeders"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
|
@ -465,7 +476,7 @@ const FeedSpecific = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="max_seeders"
|
||||
label="Max Seeders"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
|
@ -476,7 +487,7 @@ const FeedSpecific = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="min_leechers"
|
||||
label="Min Leechers"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
|
@ -487,7 +498,7 @@ const FeedSpecific = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="max_leechers"
|
||||
label="Max Leechers"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
|
@ -522,22 +533,22 @@ const RawReleaseTags = () => {
|
|||
}
|
||||
/>
|
||||
|
||||
<Components.Layout>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout>
|
||||
<SwitchGroup
|
||||
name="use_regex_release_tags"
|
||||
label="Use Regex"
|
||||
className="col-span-12 sm:col-span-6"
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Input.RegexField
|
||||
<RegexField
|
||||
name="match_release_tags"
|
||||
label="Match release tags"
|
||||
useRegex={values.use_regex_release_tags}
|
||||
columns={6}
|
||||
placeholder="eg. *mkv*,*foreign*"
|
||||
/>
|
||||
<Input.RegexField
|
||||
<RegexField
|
||||
name="except_release_tags"
|
||||
label="Except release tags"
|
||||
useRegex={values.use_regex_release_tags}
|
||||
|
|
|
@ -23,8 +23,7 @@ import { DeleteModal } from "@components/modals";
|
|||
import { DocsLink } from "@components/ExternalLink";
|
||||
import { Checkbox } from "@components/Checkbox";
|
||||
import { TitleSubtitle } from "@components/headings";
|
||||
|
||||
import * as FilterSection from "./_components";
|
||||
import { FilterHalfRow, FilterLayout, FilterPage, FilterSection } from "@screens/filters/sections/_components.tsx";
|
||||
|
||||
export function External() {
|
||||
const { values } = useFormikContext<Filter>();
|
||||
|
@ -197,13 +196,13 @@ function FilterExternalItem({ idx, external, initialEdit, remove, move }: Filter
|
|||
text="Are you sure you want to remove this external filter? This action cannot be undone."
|
||||
/>
|
||||
|
||||
<FilterSection.Page gap="sm:gap-y-6">
|
||||
<FilterSection.Section
|
||||
<FilterPage gap="sm:gap-y-6">
|
||||
<FilterSection
|
||||
title="External Filter"
|
||||
subtitle="Define the type of your filter and its name"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<Select
|
||||
name={`external.${idx}.type`}
|
||||
label="Type"
|
||||
|
@ -211,13 +210,13 @@ function FilterExternalItem({ idx, external, initialEdit, remove, move }: Filter
|
|||
options={ExternalFilterTypeOptions}
|
||||
tooltip={<div><p>Select the type for this external filter.</p></div>}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<FilterSection.HalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField name={`external.${idx}.name`} label="Name" />
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<TypeForm external={external} idx={idx} />
|
||||
|
||||
|
@ -238,7 +237,7 @@ function FilterExternalItem({ idx, external, initialEdit, remove, move }: Filter
|
|||
Close
|
||||
</button>
|
||||
</div>
|
||||
</FilterSection.Page>
|
||||
</FilterPage>
|
||||
</div>
|
||||
)}
|
||||
</li>
|
||||
|
@ -255,11 +254,11 @@ const TypeForm = ({ external, idx }: TypeFormProps) => {
|
|||
switch (external.type) {
|
||||
case "EXEC": {
|
||||
return (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Execute"
|
||||
subtitle="Specify the executable, the argument and the expected exit status to run as a pre-filter"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name={`external.${idx}.exec_cmd`}
|
||||
label="Path to Executable"
|
||||
|
@ -288,18 +287,18 @@ const TypeForm = ({ external, idx }: TypeFormProps) => {
|
|||
placeholder="0"
|
||||
/>
|
||||
</div>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
}
|
||||
case "WEBHOOK": {
|
||||
return (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Request"
|
||||
subtitle="Specify your request destination endpoint, headers and expected return status"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name={`external.${idx}.webhook_host`}
|
||||
label="Endpoint"
|
||||
|
@ -325,13 +324,13 @@ const TypeForm = ({ external, idx }: TypeFormProps) => {
|
|||
label="Expected HTTP status code"
|
||||
placeholder="200"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
<FilterSection.Section
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
<FilterSection
|
||||
title="Retry"
|
||||
subtitle="Retry behavior on request failure"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name={`external.${idx}.webhook_retry_status`}
|
||||
label="Retry http status code(s)"
|
||||
|
@ -348,20 +347,20 @@ const TypeForm = ({ external, idx }: TypeFormProps) => {
|
|||
label="Retry delay in seconds"
|
||||
placeholder="1"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
<FilterSection.Section
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
<FilterSection
|
||||
title="Payload"
|
||||
subtitle="Specify your JSON payload"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name={`external.${idx}.webhook_data`}
|
||||
label="Data (json)"
|
||||
placeholder={"Request data: { \"key\": \"value\" }"}
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -9,13 +9,12 @@ import { downloadsPerUnitOptions } from "@domain/constants";
|
|||
import { IndexersOptionsQueryOptions } from "@api/queries";
|
||||
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
|
||||
import * as Input from "@components/inputs";
|
||||
import * as Components from "./_components";
|
||||
import { FilterLayout, FilterPage, FilterSection } from "./_components";
|
||||
import { IndexerMultiSelect, MultiSelectOption, NumberField, Select, SwitchGroup, TextField } from "@components/inputs";
|
||||
|
||||
|
||||
const MapIndexer = (indexer: Indexer) => (
|
||||
{ label: indexer.name, value: indexer.id } as Input.MultiSelectOption
|
||||
{ label: indexer.name, value: indexer.id } as MultiSelectOption
|
||||
);
|
||||
|
||||
export const General = () => {
|
||||
|
@ -25,23 +24,23 @@ export const General = () => {
|
|||
// const indexerOptions = data?.map(MapIndexer) ?? [];
|
||||
|
||||
return (
|
||||
<Components.Page>
|
||||
<Components.Section>
|
||||
<Components.Layout>
|
||||
<Input.TextField name="name" label="Filter name" columns={6} placeholder="eg. Filter 1" />
|
||||
<FilterPage>
|
||||
<FilterSection>
|
||||
<FilterLayout>
|
||||
<TextField name="name" label="Filter name" columns={6} placeholder="eg. Filter 1" />
|
||||
|
||||
{/*{!isLoading && (*/}
|
||||
<Input.IndexerMultiSelect name="indexers" options={indexerOptions} label="Indexers" columns={6} />
|
||||
<IndexerMultiSelect name="indexers" options={indexerOptions} label="Indexers" columns={6} />
|
||||
{/*)}*/}
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<Components.Section
|
||||
<FilterSection
|
||||
title="Rules"
|
||||
subtitle="Specify rules on how torrents should be handled/selected."
|
||||
>
|
||||
<Components.Layout>
|
||||
<Input.TextField
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name="min_size"
|
||||
label="Min size"
|
||||
columns={6}
|
||||
|
@ -53,7 +52,7 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextField
|
||||
<TextField
|
||||
name="max_size"
|
||||
label="Max size"
|
||||
columns={6}
|
||||
|
@ -65,7 +64,7 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="delay"
|
||||
label="Delay"
|
||||
placeholder="Number of seconds to delay actions"
|
||||
|
@ -76,7 +75,7 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="priority"
|
||||
label="Priority"
|
||||
placeholder="Higher number = higher priority"
|
||||
|
@ -87,7 +86,7 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name="max_downloads"
|
||||
label="Max downloads"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
|
@ -98,7 +97,7 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name="max_downloads_unit"
|
||||
label="Max downloads per"
|
||||
options={downloadsPerUnitOptions}
|
||||
|
@ -110,17 +109,17 @@ export const General = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout>
|
||||
<SwitchGroup
|
||||
name="enabled"
|
||||
label="Enabled"
|
||||
description="Enable or disable this filter."
|
||||
className="pb-2 col-span-12 sm:col-span-6"
|
||||
/>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</Components.Page>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
</FilterPage>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -8,14 +8,19 @@ import { TextAreaAutoResize } from "@components/inputs/input";
|
|||
import { MultiSelect, SwitchGroup, TextField } from "@components/inputs";
|
||||
|
||||
import * as CONSTS from "@domain/constants";
|
||||
import * as Components from "./_components";
|
||||
import {
|
||||
FilterLayout,
|
||||
FilterPage,
|
||||
FilterSection,
|
||||
FilterWideGridGapClass
|
||||
} from "@screens/filters/sections/_components.tsx";
|
||||
|
||||
const SeasonsAndEpisodes = () => (
|
||||
<Components.Section
|
||||
<FilterSection
|
||||
title="Seasons, Episodes and Date"
|
||||
subtitle="Set season, episode, year, months and day match constraints."
|
||||
>
|
||||
<Components.Layout>
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name="seasons"
|
||||
label="Seasons"
|
||||
|
@ -84,16 +89,16 @@ const SeasonsAndEpisodes = () => (
|
|||
description="Do not match episodes older than the last one matched."
|
||||
/>
|
||||
</div>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
const Quality = () => (
|
||||
<Components.Section
|
||||
<FilterSection
|
||||
title="Quality"
|
||||
subtitle="Set resolution, source, codec and related match constraints."
|
||||
>
|
||||
<Components.Layout gap={Components.WideGridGapClass}>
|
||||
<FilterLayout gap={FilterWideGridGapClass}>
|
||||
<MultiSelect
|
||||
name="resolutions"
|
||||
options={CONSTS.RESOLUTION_OPTIONS}
|
||||
|
@ -118,9 +123,9 @@ const Quality = () => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout gap={Components.WideGridGapClass}>
|
||||
<FilterLayout gap={FilterWideGridGapClass}>
|
||||
<MultiSelect
|
||||
name="codecs"
|
||||
options={CONSTS.CODECS_OPTIONS}
|
||||
|
@ -145,9 +150,9 @@ const Quality = () => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout gap={Components.WideGridGapClass}>
|
||||
<FilterLayout gap={FilterWideGridGapClass}>
|
||||
<MultiSelect
|
||||
name="match_hdr"
|
||||
options={CONSTS.HDR_OPTIONS}
|
||||
|
@ -172,9 +177,9 @@ const Quality = () => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout gap={Components.WideGridGapClass}>
|
||||
<FilterLayout gap={FilterWideGridGapClass}>
|
||||
<MultiSelect
|
||||
name="match_other"
|
||||
options={CONSTS.OTHER_OPTIONS}
|
||||
|
@ -199,14 +204,14 @@ const Quality = () => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
export const MoviesTv = () => (
|
||||
<Components.Page>
|
||||
<Components.Section>
|
||||
<Components.Layout>
|
||||
<FilterPage>
|
||||
<FilterSection>
|
||||
<FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name="shows"
|
||||
label="Movies / Shows"
|
||||
|
@ -231,10 +236,10 @@ export const MoviesTv = () => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<SeasonsAndEpisodes />
|
||||
<Quality />
|
||||
</Components.Page>
|
||||
</FilterPage>
|
||||
);
|
||||
|
|
|
@ -6,19 +6,20 @@
|
|||
import { useFormikContext } from "formik";
|
||||
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
import * as Input from "@components/inputs";
|
||||
import { FilterLayout, FilterPage, FilterRow, FilterSection } from "./_components";
|
||||
import { MultiSelect, NumberField, SwitchGroup, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
import * as CONSTS from "@domain/constants";
|
||||
import * as Components from "./_components";
|
||||
|
||||
|
||||
export const Music = () => {
|
||||
const { values } = useFormikContext<Filter>();
|
||||
|
||||
return (
|
||||
<Components.Page>
|
||||
<Components.Section>
|
||||
<Components.Layout>
|
||||
<Input.TextAreaAutoResize
|
||||
<FilterPage>
|
||||
<FilterSection>
|
||||
<FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name="artists"
|
||||
label="Artists"
|
||||
columns={6}
|
||||
|
@ -30,7 +31,7 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name="albums"
|
||||
label="Albums"
|
||||
columns={6}
|
||||
|
@ -42,15 +43,15 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<Components.Section
|
||||
<FilterSection
|
||||
title="Release details"
|
||||
subtitle="Type (Album, Single, EP, etc.) and year of release (if announced)"
|
||||
>
|
||||
<Components.Layout>
|
||||
<Input.MultiSelect
|
||||
<FilterLayout>
|
||||
<MultiSelect
|
||||
name="match_release_types"
|
||||
options={CONSTS.RELEASE_TYPE_MUSIC_OPTIONS}
|
||||
label="Music Type"
|
||||
|
@ -62,7 +63,7 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.TextField
|
||||
<TextField
|
||||
name="years"
|
||||
label="Years"
|
||||
columns={6}
|
||||
|
@ -74,16 +75,16 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
|
||||
<Components.Section
|
||||
<FilterSection
|
||||
title="Quality"
|
||||
subtitle="Format, source, log, etc."
|
||||
>
|
||||
<Components.Layout>
|
||||
<Components.Layout>
|
||||
<Input.MultiSelect
|
||||
<FilterLayout>
|
||||
<FilterLayout>
|
||||
<MultiSelect
|
||||
name="formats"
|
||||
options={CONSTS.FORMATS_OPTIONS}
|
||||
label="Format"
|
||||
|
@ -96,7 +97,7 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="quality"
|
||||
options={CONSTS.QUALITY_MUSIC_OPTIONS}
|
||||
label="Quality"
|
||||
|
@ -109,7 +110,7 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
<Input.MultiSelect
|
||||
<MultiSelect
|
||||
name="media"
|
||||
options={CONSTS.SOURCES_MUSIC_OPTIONS}
|
||||
label="Media"
|
||||
|
@ -122,31 +123,31 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<Components.Layout className="items-end sm:!gap-x-6">
|
||||
<Components.Row className="sm:col-span-4">
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout className="items-end sm:!gap-x-6">
|
||||
<FilterRow className="sm:col-span-4">
|
||||
<SwitchGroup
|
||||
name="cue"
|
||||
label="Cue"
|
||||
description="Must include CUE info"
|
||||
disabled={values.perfect_flac}
|
||||
className="sm:col-span-4"
|
||||
/>
|
||||
</Components.Row>
|
||||
</FilterRow>
|
||||
|
||||
<Components.Row className="sm:col-span-4">
|
||||
<Input.SwitchGroup
|
||||
<FilterRow className="sm:col-span-4">
|
||||
<SwitchGroup
|
||||
name="log"
|
||||
label="Log"
|
||||
description="Must include LOG info"
|
||||
disabled={values.perfect_flac}
|
||||
className="sm:col-span-4"
|
||||
/>
|
||||
</Components.Row>
|
||||
</FilterRow>
|
||||
|
||||
<Components.Row className="sm:col-span-4">
|
||||
<Input.NumberField
|
||||
<FilterRow className="sm:col-span-4">
|
||||
<NumberField
|
||||
name="log_score"
|
||||
label="Log score"
|
||||
placeholder="eg. 100"
|
||||
|
@ -160,9 +161,9 @@ export const Music = () => {
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</Components.Row>
|
||||
</Components.Layout>
|
||||
</Components.Layout>
|
||||
</FilterRow>
|
||||
</FilterLayout>
|
||||
</FilterLayout>
|
||||
|
||||
<div className="col-span-12 flex items-center justify-center">
|
||||
<span className="border-b border-gray-150 dark:border-gray-750 w-full" />
|
||||
|
@ -172,8 +173,8 @@ export const Music = () => {
|
|||
<span className="border-b border-gray-150 dark:border-gray-750 w-full" />
|
||||
</div>
|
||||
|
||||
<Components.Layout className="sm:!gap-x-6">
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout className="sm:!gap-x-6">
|
||||
<SwitchGroup
|
||||
name="perfect_flac"
|
||||
label="Perfect FLAC"
|
||||
description="Override all options about quality, source, format, and cue/log/log score."
|
||||
|
@ -189,8 +190,8 @@ export const Music = () => {
|
|||
<span className="col-span-12 sm:col-span-6 self-center ml-0 text-center sm:text-left text-sm text-gray-500 dark:text-gray-425 underline underline-offset-2">
|
||||
This is what you want in 90% of cases (instead of options above).
|
||||
</span>
|
||||
</Components.Layout>
|
||||
</Components.Section>
|
||||
</Components.Page>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
</FilterPage>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,41 +24,41 @@ type OwningComponent = {
|
|||
|
||||
const VerticalGap = "gap-y-6 sm:gap-y-4";
|
||||
|
||||
export const NormalGridGapClass = `gap-x-0.5 sm:gap-x-3 ${VerticalGap}`;
|
||||
export const TightGridGapClass = `gap-x-0.5 sm:gap-x-1.5 ${VerticalGap}`;
|
||||
export const WideGridGapClass = `gap-x-0.5 sm:gap-x-6 ${VerticalGap}`;
|
||||
export const FilterNormalGridGapClass = `gap-x-0.5 sm:gap-x-3 ${VerticalGap}`;
|
||||
export const FilterTightGridGapClass = `gap-x-0.5 sm:gap-x-1.5 ${VerticalGap}`;
|
||||
export const FilterWideGridGapClass = `gap-x-0.5 sm:gap-x-6 ${VerticalGap}`;
|
||||
|
||||
export const LayoutClass = "grid grid-cols-12 col-span-12";
|
||||
export const FilterLayoutClass = "grid grid-cols-12 col-span-12";
|
||||
|
||||
export const Layout = ({
|
||||
export const FilterLayout = ({
|
||||
children,
|
||||
className = "",
|
||||
gap = NormalGridGapClass
|
||||
gap = FilterNormalGridGapClass
|
||||
}: OwningComponent) => (
|
||||
<div className={classNames(className, LayoutClass, gap)}>{children}</div>
|
||||
<div className={classNames(className, FilterLayoutClass, gap)}>{children}</div>
|
||||
);
|
||||
|
||||
export const Row = ({
|
||||
export const FilterRow = ({
|
||||
children,
|
||||
className = "",
|
||||
gap = NormalGridGapClass
|
||||
gap = FilterNormalGridGapClass
|
||||
}: OwningComponent) => (
|
||||
<div className={classNames(className, gap, "col-span-12")}>{children}</div>
|
||||
);
|
||||
|
||||
export const HalfRow = ({
|
||||
export const FilterHalfRow = ({
|
||||
children,
|
||||
className = "",
|
||||
gap = NormalGridGapClass
|
||||
gap = FilterNormalGridGapClass
|
||||
}: OwningComponent) => (
|
||||
<div className={classNames(className, gap, "col-span-12 sm:col-span-6")}>{children}</div>
|
||||
);
|
||||
|
||||
export const Section = ({
|
||||
export const FilterSection = ({
|
||||
title,
|
||||
subtitle,
|
||||
children,
|
||||
gap = NormalGridGapClass
|
||||
gap = FilterNormalGridGapClass
|
||||
}: FilterSectionProps) => (
|
||||
<div
|
||||
className={classNames(
|
||||
|
@ -79,7 +79,7 @@ type FilterPageProps = {
|
|||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
export const Page = ({
|
||||
export const FilterPage = ({
|
||||
gap = VerticalGap,
|
||||
children
|
||||
}: FilterPageProps) => (
|
||||
|
@ -108,7 +108,7 @@ export const CollapsibleSection = ({
|
|||
children,
|
||||
defaultOpen = false,
|
||||
noBottomBorder = false,
|
||||
childClassName = NormalGridGapClass
|
||||
childClassName = FilterNormalGridGapClass
|
||||
}: CollapsibleSectionProps) => {
|
||||
const [isOpen, toggleOpen] = useToggle(defaultOpen);
|
||||
|
||||
|
|
|
@ -3,77 +3,75 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import * as Input from "@components/inputs";
|
||||
|
||||
import { CollapsibleSection } from "../_components";
|
||||
import * as FilterSection from "../_components";
|
||||
import { CollapsibleSection, FilterHalfRow, FilterLayout, FilterSection } from "../_components";
|
||||
import { DownloadClientSelect, NumberField, SwitchGroup, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
export const Deluge = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.TextField
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField
|
||||
name={`actions.${idx}.label`}
|
||||
label="Label"
|
||||
columns={6}
|
||||
placeholder="eg. label1 (must exist in Deluge to work)"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.save_path`}
|
||||
label="Save path"
|
||||
placeholder="eg. /full/path/to/download_folder"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<FilterSection.Layout className="pb-6">
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout className="pb-6">
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.paused`}
|
||||
label="Add paused"
|
||||
description="Add torrent as paused"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.skip_hash_check`}
|
||||
label="Skip hash check"
|
||||
description="Add torrent and skip hash check"
|
||||
tooltip={<div>This will only work on Deluge v2.</div>}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<CollapsibleSection
|
||||
noBottomBorder
|
||||
title="Limits"
|
||||
subtitle="Configure your speed/ratio/seed time limits"
|
||||
>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_download_speed`}
|
||||
label="Limit download speed (KB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_upload_speed`}
|
||||
label="Limit upload speed (KB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</CollapsibleSection>
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,29 +3,27 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import * as Input from "@components/inputs";
|
||||
|
||||
import { CollapsibleSection } from "../_components";
|
||||
import * as FilterSection from "../_components";
|
||||
import { CollapsibleSection, FilterHalfRow, FilterLayout, FilterSection } from "../_components";
|
||||
import { DownloadClientSelect, NumberField, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
export const Porla = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.TextField
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField
|
||||
name={`actions.${idx}.label`}
|
||||
label="Preset"
|
||||
placeholder="eg. default"
|
||||
|
@ -33,10 +31,10 @@ export const Porla = ({ idx, action, clients }: ClientActionProps) => (
|
|||
<div>A case-sensitive preset name as configured in Porla.</div>
|
||||
}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.save_path`}
|
||||
label="Save path"
|
||||
placeholder="eg. /full/path/to/torrent/data"
|
||||
|
@ -48,21 +46,21 @@ export const Porla = ({ idx, action, clients }: ClientActionProps) => (
|
|||
title="Limits"
|
||||
subtitle="Configure your speed/ratio/seed time limits"
|
||||
>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.NumberField
|
||||
<FilterHalfRow>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_download_speed`}
|
||||
label="Limit download speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.NumberField
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_upload_speed`}
|
||||
label="Limit upload speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
</CollapsibleSection>
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -7,31 +7,37 @@ import { Link } from "@tanstack/react-router";
|
|||
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
import { ActionContentLayoutOptions, ActionPriorityOptions } from "@domain/constants";
|
||||
import * as Input from "@components/inputs";
|
||||
|
||||
import { CollapsibleSection } from "../_components";
|
||||
import * as FilterSection from "../_components";
|
||||
import { CollapsibleSection, FilterHalfRow, FilterLayout, FilterSection, FilterWideGridGapClass } from "../_components";
|
||||
import {
|
||||
DownloadClientSelect,
|
||||
NumberField,
|
||||
Select,
|
||||
SwitchGroup,
|
||||
TextAreaAutoResize,
|
||||
TextField
|
||||
} from "@components/inputs";
|
||||
|
||||
export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<FilterSection.Layout>
|
||||
<Input.TextField
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name={`actions.${idx}.category`}
|
||||
label="Category"
|
||||
columns={6}
|
||||
|
@ -44,7 +50,7 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
|||
}
|
||||
/>
|
||||
|
||||
<Input.TextField
|
||||
<TextField
|
||||
name={`actions.${idx}.tags`}
|
||||
label="Tags"
|
||||
columns={6}
|
||||
|
@ -56,10 +62,10 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<FilterSection.Layout className="pb-6">
|
||||
<Input.TextAreaAutoResize
|
||||
<FilterLayout className="pb-6">
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.save_path`}
|
||||
label="Save path"
|
||||
placeholder="eg. /full/path/to/download_folder"
|
||||
|
@ -72,15 +78,15 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<CollapsibleSection
|
||||
title="Rules"
|
||||
subtitle="Configure your torrent client rules"
|
||||
childClassName={FilterSection.WideGridGapClass}
|
||||
childClassName={FilterWideGridGapClass}
|
||||
>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.ignore_rules`}
|
||||
label="Ignore existing client rules"
|
||||
description={
|
||||
|
@ -90,14 +96,14 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
|||
}
|
||||
className="py-2 pb-4"
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name={`actions.${idx}.content_layout`}
|
||||
label="Content Layout"
|
||||
optionDefaultText="Select content layout"
|
||||
options={ActionContentLayoutOptions}
|
||||
className="py-2 pb-4"
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name={`actions.${idx}.priority`}
|
||||
label="Priority"
|
||||
optionDefaultText="Disabled"
|
||||
|
@ -108,94 +114,94 @@ export const QBittorrent = ({ idx, action, clients }: ClientActionProps) => (
|
|||
</div>
|
||||
}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.paused`}
|
||||
label="Add paused"
|
||||
description="Add torrent as paused"
|
||||
/>
|
||||
<Input.SwitchGroup
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.skip_hash_check`}
|
||||
label="Skip hash check"
|
||||
description="Add torrent and skip hash check"
|
||||
className="pt-4 sm:pt-4"
|
||||
/>
|
||||
<Input.SwitchGroup
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.first_last_piece_prio`}
|
||||
label="Download first and last pieces first"
|
||||
description="Add torrent and download first and last pieces first"
|
||||
className="pt-6 sm:pt-10"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
</CollapsibleSection>
|
||||
|
||||
<CollapsibleSection
|
||||
title="Limits"
|
||||
subtitle="Configure your speed/ratio/seed time limits"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<Input.NumberField
|
||||
<FilterLayout>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_download_speed`}
|
||||
label="Limit download speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_upload_speed`}
|
||||
label="Limit upload speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<FilterSection.Layout>
|
||||
<Input.NumberField
|
||||
<FilterLayout>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_ratio`}
|
||||
label="Ratio limit"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
step={0.25}
|
||||
isDecimal
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_seed_time`}
|
||||
label="Seed time limit (minutes)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
</CollapsibleSection>
|
||||
|
||||
<CollapsibleSection
|
||||
noBottomBorder
|
||||
title="Announce"
|
||||
subtitle="Set number of reannounces (if needed), delete after Y announce failures, etc."
|
||||
childClassName={FilterSection.WideGridGapClass}
|
||||
childClassName={FilterWideGridGapClass}
|
||||
>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.reannounce_skip`}
|
||||
label="Skip reannounce"
|
||||
description="If reannounce is not needed, skip it completely"
|
||||
className="pt-2 pb-4"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.reannounce_interval`}
|
||||
label="Reannounce interval. Run every X seconds"
|
||||
placeholder="7 is default and recommended"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.reannounce_delete`}
|
||||
label="Delete stalled"
|
||||
description="Delete stalled torrents after Y attempts"
|
||||
className="pt-2 pb-4"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.reannounce_max_attempts`}
|
||||
label="Run reannounce Y times"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
</CollapsibleSection>
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -4,59 +4,59 @@
|
|||
*/
|
||||
|
||||
import { ActionRtorrentRenameOptions } from "@domain/constants";
|
||||
import * as Input from "@components/inputs";
|
||||
import { FilterHalfRow, FilterLayout, FilterSection } from "@screens/filters/sections/_components.tsx";
|
||||
import { DownloadClientSelect, Select, SwitchGroup, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
import * as FilterSection from "../_components";
|
||||
|
||||
export const RTorrent = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<FilterSection.HalfRow>
|
||||
<Input.TextField
|
||||
<FilterHalfRow>
|
||||
<TextField
|
||||
name={`actions.${idx}.label`}
|
||||
label="Label"
|
||||
columns={6}
|
||||
placeholder="eg. label1,label2"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.save_path`}
|
||||
label="Save path"
|
||||
placeholder="eg. /full/path/to/download_folder"
|
||||
/>
|
||||
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.paused`}
|
||||
label="Add paused"
|
||||
description="Add torrent as paused"
|
||||
className="pt-2 pb-4"
|
||||
/>
|
||||
<Input.Select
|
||||
<Select
|
||||
name={`actions.${idx}.content_layout`}
|
||||
label="Do not add torrent name to path"
|
||||
optionDefaultText="No"
|
||||
options={ActionRtorrentRenameOptions}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -3,119 +3,117 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import * as Input from "@components/inputs";
|
||||
|
||||
import { CollapsibleSection } from "../_components";
|
||||
import * as FilterSection from "../_components";
|
||||
import { CollapsibleSection, FilterHalfRow, FilterLayout, FilterSection, FilterWideGridGapClass } from "../_components";
|
||||
import { DownloadClientSelect, NumberField, SwitchGroup, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
export const Transmission = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<>
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.TextField
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField
|
||||
name={`actions.${idx}.label`}
|
||||
label="Torrent Label"
|
||||
columns={6}
|
||||
placeholder="eg. label1"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.save_path`}
|
||||
label="Save path"
|
||||
columns={6}
|
||||
placeholder="eg. /full/path/to/download_folder"
|
||||
/>
|
||||
|
||||
<FilterSection.Layout className="pb-6">
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterLayout className="pb-6">
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.paused`}
|
||||
label="Add paused"
|
||||
description="Add torrent as paused"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
|
||||
<CollapsibleSection
|
||||
title="Limits"
|
||||
subtitle="Configure your speed/ratio/seed time limits"
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<Input.NumberField
|
||||
<FilterLayout>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_download_speed`}
|
||||
label="Limit download speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_upload_speed`}
|
||||
label="Limit upload speed (KiB/s)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
<FilterSection.Layout>
|
||||
<Input.NumberField
|
||||
<FilterLayout>
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_ratio`}
|
||||
label="Ratio limit"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
step={0.25}
|
||||
isDecimal
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.limit_seed_time`}
|
||||
label="Seed time limit (minutes)"
|
||||
placeholder="Takes any number (0 is no limit)"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
</CollapsibleSection>
|
||||
|
||||
<CollapsibleSection
|
||||
noBottomBorder
|
||||
title="Announce"
|
||||
subtitle="Set number of reannounces (if needed), delete after Y announce failures, etc."
|
||||
childClassName={FilterSection.WideGridGapClass}
|
||||
childClassName={FilterWideGridGapClass}
|
||||
>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.reannounce_skip`}
|
||||
label="Skip reannounce"
|
||||
description="If reannounce is not needed, skip it completely"
|
||||
className="pt-2 pb-4"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.reannounce_interval`}
|
||||
label="Reannounce interval. Run every X seconds"
|
||||
placeholder="7 is default and recommended"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.SwitchGroup
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<SwitchGroup
|
||||
name={`actions.${idx}.reannounce_delete`}
|
||||
label="Delete stalled"
|
||||
description="Delete stalled torrents after Y attempts"
|
||||
className="pt-2 pb-4"
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.reannounce_max_attempts`}
|
||||
label="Run reannounce Y times"
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
</CollapsibleSection>
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
</>
|
||||
);
|
||||
|
|
|
@ -4,36 +4,36 @@
|
|||
*/
|
||||
|
||||
import { WarningAlert } from "@components/alerts";
|
||||
import * as Input from "@components/inputs";
|
||||
import { FilterHalfRow, FilterLayout, FilterSection } from "@screens/filters/sections/_components.tsx";
|
||||
import { DownloadClientSelect, NumberField, TextAreaAutoResize, TextField } from "@components/inputs";
|
||||
|
||||
import * as FilterSection from "../_components";
|
||||
|
||||
export const SABnzbd = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.TextField
|
||||
</FilterHalfRow>
|
||||
<FilterHalfRow>
|
||||
<TextField
|
||||
name={`actions.${idx}.category`}
|
||||
label="Category"
|
||||
columns={6}
|
||||
placeholder="eg. category"
|
||||
tooltip={<p>Category must exist already.</p>}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
export const Test = () => (
|
||||
|
@ -46,49 +46,49 @@ export const Test = () => (
|
|||
);
|
||||
|
||||
export const Exec = ({ idx }: ClientActionProps) => (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Exec Arguments"
|
||||
subtitle="Specify the executable and its arguments to be executed upon filter match. Use an absolute path."
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<Input.TextField
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name={`actions.${idx}.exec_cmd`}
|
||||
label="Path to Executable"
|
||||
placeholder="Path to program eg. /bin/test"
|
||||
/>
|
||||
|
||||
<Input.TextAreaAutoResize
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.exec_args`}
|
||||
label="Arguments"
|
||||
placeholder="Arguments eg. --test"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterLayout>
|
||||
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
export const WatchFolder = ({ idx }: ClientActionProps) => (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Watch Folder Arguments"
|
||||
subtitle="Point to where autobrr should save the files it fetches. Use an absolute path."
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<Input.TextAreaAutoResize
|
||||
<FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.watch_folder`}
|
||||
label="Watch directory"
|
||||
placeholder="Watch directory eg. /home/user/rwatch"
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
export const WebHook = ({ idx }: ClientActionProps) => (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Webhook Arguments"
|
||||
subtitle="Specify the payload to be sent to the desired endpoint upon filter match."
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<Input.TextField
|
||||
<FilterLayout>
|
||||
<TextField
|
||||
name={`actions.${idx}.webhook_host`}
|
||||
label="Endpoint"
|
||||
columns={6}
|
||||
|
@ -97,34 +97,34 @@ export const WebHook = ({ idx }: ClientActionProps) => (
|
|||
<p>URL or IP to your API. Pass params and set API tokens etc.</p>
|
||||
}
|
||||
/>
|
||||
</FilterSection.Layout>
|
||||
<Input.TextAreaAutoResize
|
||||
</FilterLayout>
|
||||
<TextAreaAutoResize
|
||||
name={`actions.${idx}.webhook_data`}
|
||||
label="Payload (json)"
|
||||
placeholder={"Request data: { \"key\": \"value\" }"}
|
||||
/>
|
||||
</FilterSection.Section>
|
||||
</FilterSection>
|
||||
);
|
||||
|
||||
export const Arr = ({ idx, action, clients }: ClientActionProps) => (
|
||||
<FilterSection.Section
|
||||
<FilterSection
|
||||
title="Instance"
|
||||
subtitle={
|
||||
<>Select the <span className="font-bold">specific instance</span> which you want to handle this release filter.</>
|
||||
}
|
||||
>
|
||||
<FilterSection.Layout>
|
||||
<FilterSection.HalfRow>
|
||||
<Input.DownloadClientSelect
|
||||
<FilterLayout>
|
||||
<FilterHalfRow>
|
||||
<DownloadClientSelect
|
||||
name={`actions.${idx}.client_id`}
|
||||
action={action}
|
||||
clients={clients}
|
||||
/>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterHalfRow>
|
||||
|
||||
<FilterSection.HalfRow>
|
||||
<FilterHalfRow>
|
||||
<div className="">
|
||||
<Input.TextField
|
||||
<TextField
|
||||
name={`actions.${idx}.external_download_client`}
|
||||
label="Override download client name for arr"
|
||||
tooltip={
|
||||
|
@ -134,7 +134,7 @@ export const Arr = ({ idx, action, clients }: ClientActionProps) => (
|
|||
</p>
|
||||
}
|
||||
/>
|
||||
<Input.NumberField
|
||||
<NumberField
|
||||
name={`actions.${idx}.external_download_client_id`}
|
||||
label="Override download client id for arr DEPRECATED"
|
||||
className="mt-4"
|
||||
|
@ -146,7 +146,7 @@ export const Arr = ({ idx, action, clients }: ClientActionProps) => (
|
|||
}
|
||||
/>
|
||||
</div>
|
||||
</FilterSection.HalfRow>
|
||||
</FilterSection.Layout>
|
||||
</FilterSection.Section>
|
||||
</FilterHalfRow>
|
||||
</FilterLayout>
|
||||
</FilterSection>
|
||||
);
|
||||
|
|
|
@ -19,13 +19,11 @@ import {
|
|||
import { ReleasesRoute } from "@app/routes";
|
||||
import { ReleasesListQueryOptions } from "@api/queries";
|
||||
import { RandomLinuxIsos } from "@utils";
|
||||
|
||||
import * as Icons from "@components/Icons";
|
||||
import { RingResizeSpinner } from "@components/Icons";
|
||||
import * as DataTable from "@components/data-table";
|
||||
|
||||
import { RingResizeSpinner, SortDownIcon, SortIcon, SortUpIcon } from "@components/Icons";
|
||||
import { IndexerSelectColumnFilter, PushStatusSelectColumnFilter, SearchColumnFilter } from "./ReleaseFilters";
|
||||
import { EmptyListState } from "@components/emptystates";
|
||||
import { TableButton, TablePageButton } from "@components/data-table/Buttons.tsx";
|
||||
import { AgeCell, IndexerCell, LinksCell, NameCell, ReleaseStatusCell } from "@components/data-table";
|
||||
|
||||
type TableState = {
|
||||
queryPageIndex: number;
|
||||
|
@ -100,30 +98,30 @@ export const ReleaseTable = () => {
|
|||
{
|
||||
Header: "Age",
|
||||
accessor: "timestamp",
|
||||
Cell: DataTable.AgeCell
|
||||
Cell: AgeCell
|
||||
},
|
||||
{
|
||||
Header: "Release",
|
||||
accessor: "name",
|
||||
Cell: DataTable.NameCell,
|
||||
Cell: NameCell,
|
||||
Filter: SearchColumnFilter
|
||||
},
|
||||
{
|
||||
Header: "Links",
|
||||
accessor: (row) => ({ download_url: row.download_url, info_url: row.info_url }),
|
||||
id: "links",
|
||||
Cell: DataTable.LinksCell
|
||||
Cell: LinksCell
|
||||
},
|
||||
{
|
||||
Header: "Actions",
|
||||
accessor: "action_status",
|
||||
Cell: DataTable.ReleaseStatusCell,
|
||||
Cell: ReleaseStatusCell,
|
||||
Filter: PushStatusSelectColumnFilter
|
||||
},
|
||||
{
|
||||
Header: "Indexer",
|
||||
accessor: "indexer.identifier",
|
||||
Cell: DataTable.IndexerCell,
|
||||
Cell: IndexerCell,
|
||||
Filter: IndexerSelectColumnFilter,
|
||||
filter: "equal"
|
||||
}
|
||||
|
@ -303,12 +301,12 @@ export const ReleaseTable = () => {
|
|||
<span>
|
||||
{column.isSorted ? (
|
||||
column.isSortedDesc ? (
|
||||
<Icons.SortDownIcon className="w-4 h-4 text-gray-400"/>
|
||||
<SortDownIcon className="w-4 h-4 text-gray-400"/>
|
||||
) : (
|
||||
<Icons.SortUpIcon className="w-4 h-4 text-gray-400"/>
|
||||
<SortUpIcon className="w-4 h-4 text-gray-400"/>
|
||||
)
|
||||
) : (
|
||||
<Icons.SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100"/>
|
||||
<SortIcon className="w-4 h-4 text-gray-400 opacity-0 group-hover:opacity-100"/>
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
@ -350,8 +348,8 @@ export const ReleaseTable = () => {
|
|||
{/* Pagination */}
|
||||
<div className="flex items-center justify-between px-6 py-3 border-t border-gray-200 dark:border-gray-700">
|
||||
<div className="flex justify-between flex-1 sm:hidden">
|
||||
<DataTable.Button onClick={() => previousPage()} disabled={!canPreviousPage}>Previous</DataTable.Button>
|
||||
<DataTable.Button onClick={() => nextPage()} disabled={!canNextPage}>Next</DataTable.Button>
|
||||
<TableButton onClick={() => previousPage()} disabled={!canPreviousPage}>Previous</TableButton>
|
||||
<TableButton onClick={() => nextPage()} disabled={!canNextPage}>Next</TableButton>
|
||||
</div>
|
||||
<div className="hidden sm:flex-1 sm:flex sm:items-center sm:justify-between">
|
||||
<div className="flex items-baseline gap-x-2">
|
||||
|
@ -378,37 +376,37 @@ export const ReleaseTable = () => {
|
|||
</div>
|
||||
<div>
|
||||
<nav className="inline-flex -space-x-px rounded-md shadow-sm" aria-label="Pagination">
|
||||
<DataTable.PageButton
|
||||
<TablePageButton
|
||||
className="rounded-l-md"
|
||||
onClick={() => gotoPage(0)}
|
||||
disabled={!canPreviousPage}
|
||||
>
|
||||
<span className="sr-only">First</span>
|
||||
<ChevronDoubleLeftIcon className="w-4 h-4" aria-hidden="true"/>
|
||||
</DataTable.PageButton>
|
||||
<DataTable.PageButton
|
||||
</TablePageButton>
|
||||
<TablePageButton
|
||||
className="pl-1 pr-2"
|
||||
onClick={() => previousPage()}
|
||||
disabled={!canPreviousPage}
|
||||
>
|
||||
<ChevronLeftIcon className="w-4 h-4 mr-1" aria-hidden="true"/>
|
||||
<span>Prev</span>
|
||||
</DataTable.PageButton>
|
||||
<DataTable.PageButton
|
||||
</TablePageButton>
|
||||
<TablePageButton
|
||||
className="pl-2 pr-1"
|
||||
onClick={() => nextPage()}
|
||||
disabled={!canNextPage}>
|
||||
<span>Next</span>
|
||||
<ChevronRightIcon className="w-4 h-4 ml-1" aria-hidden="true"/>
|
||||
</DataTable.PageButton>
|
||||
<DataTable.PageButton
|
||||
</TablePageButton>
|
||||
<TablePageButton
|
||||
className="rounded-r-md"
|
||||
onClick={() => gotoPage(pageCount - 1)}
|
||||
disabled={!canNextPage}
|
||||
>
|
||||
<ChevronDoubleRightIcon className="w-4 h-4" aria-hidden="true"/>
|
||||
<span className="sr-only">Last</span>
|
||||
</DataTable.PageButton>
|
||||
</TablePageButton>
|
||||
</nav>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue