mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
fix(web): tooltips (#1154)
* fix broken tooltips, replace react-tooltip with react-popper-tooltip * make tooltips use ExternalLink component * fix import * get rid of unused import * fix(tooltip): set delayHide * removed unecessary comment * fix tooltip on mobile * stop tooltip label propagation (mainly for mobile devices) * added onClick convenience prop for label component wrapper (since onClick isn't propagated down) --------- Co-authored-by: soup <soup@r4tio.dev>
This commit is contained in:
parent
98df0c9040
commit
3e3454724b
32 changed files with 1171 additions and 396 deletions
|
@ -69,7 +69,6 @@
|
|||
"react-select": "^5.7.4",
|
||||
"react-table": "^7.8.0",
|
||||
"react-textarea-autosize": "^8.5.3",
|
||||
"react-tooltip": "^5.21.1",
|
||||
"stacktracey": "^2.1.8",
|
||||
"tailwindcss": "^3.3.3",
|
||||
"typescript": "^5.2.2",
|
||||
|
|
21
web/pnpm-lock.yaml
generated
21
web/pnpm-lock.yaml
generated
|
@ -128,9 +128,6 @@ dependencies:
|
|||
react-textarea-autosize:
|
||||
specifier: ^8.5.3
|
||||
version: 8.5.3(@types/react@18.2.21)(react@18.2.0)
|
||||
react-tooltip:
|
||||
specifier: ^5.21.1
|
||||
version: 5.21.1(react-dom@18.2.0)(react@18.2.0)
|
||||
stacktracey:
|
||||
specifier: ^2.1.8
|
||||
version: 2.1.8
|
||||
|
@ -2873,10 +2870,6 @@ packages:
|
|||
fsevents: 2.3.3
|
||||
dev: false
|
||||
|
||||
/classnames@2.3.2:
|
||||
resolution: {integrity: sha512-CSbhY4cFEJRe6/GQzIk5qXZ4Jeg5pcsP7b5peFSDpffpe1cqjASH/n9UTjBwOp6XpMSTwQ8Za2K5V02ueA7Tmw==}
|
||||
dev: false
|
||||
|
||||
/client-only@0.0.1:
|
||||
resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==}
|
||||
dev: false
|
||||
|
@ -4763,7 +4756,7 @@ packages:
|
|||
react: ^18.2.0
|
||||
react-dom: '>=16.6.0'
|
||||
dependencies:
|
||||
'@babel/runtime': 7.22.10
|
||||
'@babel/runtime': 7.22.11
|
||||
'@popperjs/core': 2.11.8
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
|
@ -4869,18 +4862,6 @@ packages:
|
|||
- '@types/react'
|
||||
dev: false
|
||||
|
||||
/react-tooltip@5.21.1(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-wJqF/yzK1wuJuy5/zAkVErFA609fVv1ZukhGjw44PcMvg9wL0jomnpQyz3qH1H7TWjz/wqO/OMc3ipQNjZ8zYg==}
|
||||
peerDependencies:
|
||||
react: ^18.2.0
|
||||
react-dom: '>=16.14.0'
|
||||
dependencies:
|
||||
'@floating-ui/dom': 1.5.1
|
||||
classnames: 2.3.2
|
||||
react: 18.2.0
|
||||
react-dom: 18.2.0(react@18.2.0)
|
||||
dev: false
|
||||
|
||||
/react-transition-group@4.4.5(react-dom@18.2.0)(react@18.2.0):
|
||||
resolution: {integrity: sha512-pZcd1MCJoiKiBR2NRxeCRg13uCXbydPnmB4EOeRrY7480qNWO8IIgQG6zlDkm6uRMsURXPuKq0GWtiM59a5Q6g==}
|
||||
peerDependencies:
|
||||
|
|
20
web/src/components/ExternalLink.tsx
Normal file
20
web/src/components/ExternalLink.tsx
Normal file
|
@ -0,0 +1,20 @@
|
|||
type ExternalLinkProps = {
|
||||
href: string;
|
||||
className?: string;
|
||||
children?: React.ReactNode;
|
||||
};
|
||||
|
||||
export const ExternalLink = ({ href, className, children }: ExternalLinkProps) => (
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href={href}
|
||||
className={className}
|
||||
>
|
||||
{children}
|
||||
</a>
|
||||
);
|
||||
|
||||
export const DocsLink = ({ href }: { href: string; }) => (
|
||||
<ExternalLink href={href} className="text-blue-400 visited:text-blue-400">{href}</ExternalLink>
|
||||
);
|
|
@ -6,6 +6,7 @@
|
|||
import StackTracey from "stacktracey";
|
||||
import type { FallbackProps } from "react-error-boundary";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const ErrorPage = ({ error, resetErrorBoundary }: FallbackProps) => {
|
||||
const stack = new StackTracey(error);
|
||||
|
@ -35,23 +36,19 @@ export const ErrorPage = ({ error, resetErrorBoundary }: FallbackProps) => {
|
|||
<h3 className="text-xl leading-6 text-gray-700 dark:text-gray-400 mb-4">
|
||||
Please consider reporting this error to our
|
||||
{" "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://github.com/autobrr/autobrr"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-sky-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
GitHub page
|
||||
</a>
|
||||
</ExternalLink>
|
||||
{" or to "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://discord.gg/WQ2eUycxyT"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-purple-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
our official Discord channel
|
||||
</a>
|
||||
</ExternalLink>
|
||||
.
|
||||
</h3>
|
||||
<div
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
|
||||
import { Link } from "react-router-dom";
|
||||
import { ReactComponent as Logo } from "@app/logo.svg";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const NotFound = () => {
|
||||
return (
|
||||
|
@ -21,23 +22,19 @@ export const NotFound = () => {
|
|||
<h3 className="text-xl text-center text-gray-700 dark:text-gray-400 mb-1 px-2">
|
||||
feel free to report this to our
|
||||
{" "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://github.com/autobrr/autobrr"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-sky-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
GitHub page
|
||||
</a>
|
||||
</ExternalLink>
|
||||
{" or to "}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://discord.gg/WQ2eUycxyT"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-purple-500 hover:decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
our official Discord channel
|
||||
</a>
|
||||
</ExternalLink>
|
||||
.
|
||||
</h3>
|
||||
<h3 className="text-xl text-center leading-6 text-gray-700 dark:text-gray-400 mb-8 px-2">
|
||||
|
|
|
@ -4,18 +4,18 @@
|
|||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import { toast } from "react-hot-toast";
|
||||
import { formatDistanceToNowStrict } from "date-fns";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { ArrowPathIcon, CheckIcon } from "@heroicons/react/24/solid";
|
||||
import { ClockIcon, ExclamationCircleIcon, NoSymbolIcon } from "@heroicons/react/24/outline";
|
||||
|
||||
import { classNames, simplifyDate } from "@utils";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
import { useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
import { APIClient } from "@api/APIClient";
|
||||
import { classNames, simplifyDate } from "@utils";
|
||||
import { filterKeys } from "@screens/filters/List";
|
||||
import { toast } from "react-hot-toast";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { RingResizeSpinner } from "@components/Icons";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
|
||||
interface CellProps {
|
||||
value: string;
|
||||
|
@ -35,6 +35,7 @@ export const IndexerCell = ({ value }: CellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={value}
|
||||
maxWidth="max-w-[90vw]"
|
||||
>
|
||||
|
@ -53,6 +54,7 @@ export const TitleCell = ({ value }: CellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={value}
|
||||
maxWidth="max-w-[90vw]"
|
||||
>
|
||||
|
@ -221,6 +223,7 @@ export const ReleaseStatusCell = ({ value }: ReleaseStatusCellProps) => (
|
|||
)}
|
||||
>
|
||||
<Tooltip
|
||||
requiresClick
|
||||
label={StatusCellMap[v.status].icon}
|
||||
title={StatusCellMap[v.status].textFormatter(v)}
|
||||
>
|
||||
|
|
|
@ -15,6 +15,7 @@ import Toast from "@components/notifications/Toast";
|
|||
import { LeftNav } from "./LeftNav";
|
||||
import { RightNav } from "./RightNav";
|
||||
import { MobileNav } from "./MobileNav";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const Header = () => {
|
||||
const { data: config } = useQuery({
|
||||
|
@ -77,13 +78,13 @@ export const Header = () => {
|
|||
</div>
|
||||
|
||||
{data?.html_url && (
|
||||
<a href={data.html_url} target="_blank" rel="noopener noreferrer">
|
||||
<ExternalLink href={data.html_url}>
|
||||
<div className="flex mt-4 py-2 bg-blue-500 rounded justify-center">
|
||||
<MegaphoneIcon className="h-6 w-6 text-blue-100" />
|
||||
<span className="text-blue-100 font-medium mx-3">New update available!</span>
|
||||
<span className="inline-flex items-center rounded-md bg-blue-100 px-2.5 py-0.5 text-sm font-medium text-blue-800">{data?.name}</span>
|
||||
</div>
|
||||
</a>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import { classNames } from "@utils";
|
|||
import { ReactComponent as Logo } from "@app/logo.svg";
|
||||
|
||||
import { NAV_ROUTES } from "./_shared";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const LeftNav = () => (
|
||||
<div className="flex items-center">
|
||||
|
@ -38,9 +39,7 @@ export const LeftNav = () => (
|
|||
{item.name}
|
||||
</NavLink>
|
||||
))}
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href="https://autobrr.com"
|
||||
className={classNames(
|
||||
"text-gray-600 dark:text-gray-500 hover:bg-gray-200 dark:hover:bg-gray-800 hover:text-gray-900 dark:hover:text-white px-3 py-2 rounded-2xl text-sm font-medium",
|
||||
|
@ -52,7 +51,7 @@ export const LeftNav = () => (
|
|||
className="inline ml-1 h-5 w-5"
|
||||
aria-hidden="true"
|
||||
/>
|
||||
</a>
|
||||
</ExternalLink>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
|
||||
import { Field, FieldProps } from "formik";
|
||||
import { classNames } from "@utils";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface ErrorFieldProps {
|
||||
name: string;
|
||||
|
@ -63,10 +63,9 @@ const CheckboxField = ({
|
|||
<div className="ml-3 text-sm">
|
||||
<label htmlFor={name} className="flex mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
<p className="text-gray-500">{sublabel}</p>
|
||||
|
@ -74,4 +73,4 @@ const CheckboxField = ({
|
|||
</div>
|
||||
);
|
||||
|
||||
export { ErrorField, RequiredField, CheckboxField };
|
||||
export { ErrorField, RequiredField, CheckboxField };
|
||||
|
|
|
@ -9,7 +9,7 @@ import { EyeIcon, EyeSlashIcon, CheckCircleIcon, XCircleIcon } from "@heroicons/
|
|||
import TextareaAutosize from "react-textarea-autosize";
|
||||
|
||||
import { useToggle } from "@hooks/hooks";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
import { classNames } from "@utils";
|
||||
|
||||
type COL_WIDTHS = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
|
||||
|
@ -46,10 +46,9 @@ export const TextField = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -185,8 +184,9 @@ export const RegexField = ({
|
|||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
<span className="z-10">{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}</span>
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -324,9 +324,10 @@ export const RegexTextAreaField = ({
|
|||
htmlFor={name}
|
||||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
<span className="z-10">{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}</span>
|
||||
<div className="flex z-10">
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -412,10 +413,9 @@ export const TextArea = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -484,10 +484,9 @@ export const TextAreaAutoResize = ({
|
|||
{label && (
|
||||
<label htmlFor={name} className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
)}
|
||||
|
@ -630,8 +629,9 @@ export const NumberField = ({
|
|||
className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && <CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import { Switch } from "@headlessui/react";
|
|||
import { ErrorField, RequiredField } from "./common";
|
||||
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
||||
import { SelectFieldProps } from "./select";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface TextFieldWideProps {
|
||||
name: string;
|
||||
|
@ -43,7 +43,9 @@ export const TextFieldWide = ({
|
|||
<div>
|
||||
<label htmlFor={name} className="flex text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -108,7 +110,9 @@ export const PasswordFieldWide = ({
|
|||
<div>
|
||||
<label htmlFor={name} className="flex text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -172,7 +176,9 @@ export const NumberFieldWide = ({
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
<RequiredField required={required} />
|
||||
</div>
|
||||
</label>
|
||||
|
@ -232,10 +238,11 @@ export const SwitchGroupWide = ({
|
|||
<ul className="px-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||
<Switch.Group as="li" className="py-4 flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
<Switch.Label as="div" className="text-sm font-medium text-gray-900 dark:text-white"
|
||||
passive>
|
||||
<Switch.Label as="div" passive className="text-sm font-medium text-gray-900 dark:text-white">
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</Switch.Label>
|
||||
{description && (
|
||||
|
@ -396,8 +403,9 @@ export const SelectFieldWide = ({
|
|||
className="flex text-sm font-medium text-gray-900 dark:text-white"
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -11,7 +11,7 @@ import { MultiSelect as RMSC } from "react-multi-select-component";
|
|||
|
||||
import { classNames, COL_WIDTHS } from "@utils";
|
||||
import { SettingsContext } from "@utils/Context";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
export interface MultiSelectOption {
|
||||
value: string | number;
|
||||
|
@ -56,10 +56,9 @@ export const MultiSelect = ({
|
|||
<label
|
||||
htmlFor={label} className="flex mb-2 text-xs font-bold tracking-wide text-gray-700 uppercase dark:text-gray-200">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
|
||||
|
@ -297,10 +296,9 @@ export const Select = ({
|
|||
<>
|
||||
<Listbox.Label className="flex float-left mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide">
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</Listbox.Label>
|
||||
<div className="mt-2 relative">
|
||||
|
|
|
@ -8,7 +8,7 @@ import { Field } from "formik";
|
|||
import Select, { components, ControlProps, InputProps, MenuProps, OptionProps } from "react-select";
|
||||
import { OptionBasicTyped } from "@domain/constants";
|
||||
import CreatableSelect from "react-select/creatable";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
interface SelectFieldProps<T> {
|
||||
name: string;
|
||||
|
@ -29,7 +29,9 @@ export function SelectFieldCreatable<T>({ name, label, help, placeholder, toolti
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
@ -200,7 +202,9 @@ export function SelectFieldBasic<T>({ name, label, help, placeholder, tooltip, d
|
|||
className="block text-sm font-medium text-gray-900 dark:text-white sm:pt-2"
|
||||
>
|
||||
<div className="flex">
|
||||
{label} {tooltip && (<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</label>
|
||||
</div>
|
||||
|
|
|
@ -9,7 +9,7 @@ import { Field } from "formik";
|
|||
import { Switch as HeadlessSwitch } from "@headlessui/react";
|
||||
|
||||
import { classNames } from "@utils";
|
||||
import { CustomTooltip } from "@components/tooltips/CustomTooltip";
|
||||
import { DocsTooltip } from "@components/tooltips/DocsTooltip";
|
||||
|
||||
type SwitchProps<V = unknown> = {
|
||||
label?: string
|
||||
|
@ -88,13 +88,18 @@ const SwitchGroup = ({
|
|||
}: SwitchGroupProps) => (
|
||||
<HeadlessSwitch.Group as="ol" className="py-4 flex items-center justify-between">
|
||||
{label && <div className="flex flex-col">
|
||||
<HeadlessSwitch.Label as={heading ? "h2" : "span"} className={classNames("flex float-left cursor-default mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide", heading ? "text-lg" : "text-sm")}
|
||||
passive>
|
||||
<HeadlessSwitch.Label
|
||||
passive
|
||||
as={heading ? "h2" : "span"}
|
||||
className={classNames(
|
||||
"flex float-left cursor-default mb-2 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide",
|
||||
heading ? "text-lg" : "text-sm"
|
||||
)}
|
||||
>
|
||||
<div className="flex">
|
||||
{label}
|
||||
{tooltip && (
|
||||
<CustomTooltip anchorId={name}>{tooltip}</CustomTooltip>
|
||||
)}
|
||||
{tooltip ? (
|
||||
<DocsTooltip label={label}>{tooltip}</DocsTooltip>
|
||||
) : label}
|
||||
</div>
|
||||
</HeadlessSwitch.Label>
|
||||
{description && (
|
||||
|
|
|
@ -1,16 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
.react-tooltip code {
|
||||
background-color: rgb(63, 71, 94);
|
||||
padding-left: 4px;
|
||||
padding-right: 4px;
|
||||
padding-top: 2px;
|
||||
padding-bottom: 2px;
|
||||
}
|
||||
|
||||
.react-tooltip a:hover {
|
||||
text-decoration-line: underline;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import { PlacesType, Tooltip } from "react-tooltip";
|
||||
import "./CustomTooltip.css";
|
||||
|
||||
|
||||
interface CustomTooltipProps {
|
||||
anchorId: string;
|
||||
children?: React.ReactNode;
|
||||
clickable?: boolean;
|
||||
place?: PlacesType;
|
||||
}
|
||||
|
||||
export const CustomTooltip = ({
|
||||
anchorId,
|
||||
children,
|
||||
clickable = true,
|
||||
place = "top"
|
||||
}: CustomTooltipProps) => {
|
||||
const id = `${anchorId}-tooltip`;
|
||||
return (
|
||||
<div className="flex items-center">
|
||||
<svg id={id} className="ml-1 w-4 h-4 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10"/></svg>
|
||||
<Tooltip
|
||||
style={{ maxWidth: "350px", fontSize: "12px", textTransform: "none", fontWeight: "normal", borderRadius: "0.375rem", backgroundColor: "#34343A", color: "#fff" }}
|
||||
delayShow={100}
|
||||
delayHide={150}
|
||||
place={place}
|
||||
anchorSelect={id}
|
||||
data-html={true}
|
||||
clickable={clickable}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
</div>
|
||||
);
|
||||
};
|
25
web/src/components/tooltips/DocsTooltip.tsx
Normal file
25
web/src/components/tooltips/DocsTooltip.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
/*
|
||||
* Copyright (c) 2021 - 2023, Ludvig Lundgren and the autobrr contributors.
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import { Tooltip } from "./Tooltip";
|
||||
|
||||
interface DocsTooltipProps {
|
||||
label?: React.ReactNode;
|
||||
children?: React.ReactNode;
|
||||
}
|
||||
|
||||
export const DocsTooltip = ({ label, children }: DocsTooltipProps) => (
|
||||
<Tooltip
|
||||
label={
|
||||
<div className="flex flex-row items-center">
|
||||
{label ?? null}
|
||||
<svg className="ml-1 w-4 h-4 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10" /></svg>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</Tooltip>
|
||||
);
|
||||
|
|
@ -3,22 +3,30 @@
|
|||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*/
|
||||
|
||||
import * as React from "react";
|
||||
import type { ReactNode } from "react";
|
||||
import { Transition } from "@headlessui/react";
|
||||
import { usePopperTooltip } from "react-popper-tooltip";
|
||||
|
||||
import { classNames } from "@utils";
|
||||
|
||||
interface TooltipProps {
|
||||
label: ReactNode;
|
||||
onLabelClick?: (e: React.MouseEvent<HTMLDivElement>) => void;
|
||||
title?: ReactNode;
|
||||
maxWidth?: string;
|
||||
requiresClick?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
// NOTE(stacksmash76): onClick is not propagated
|
||||
// to the label (always-visible) component, so you will have
|
||||
// to use the `onLabelClick` prop in this case.
|
||||
export const Tooltip = ({
|
||||
label,
|
||||
onLabelClick,
|
||||
title,
|
||||
children,
|
||||
requiresClick,
|
||||
maxWidth = "max-w-sm"
|
||||
}: TooltipProps) => {
|
||||
const {
|
||||
|
@ -28,22 +36,46 @@ export const Tooltip = ({
|
|||
setTriggerRef,
|
||||
visible
|
||||
} = usePopperTooltip({
|
||||
trigger: ["click"],
|
||||
interactive: false
|
||||
trigger: requiresClick ? ["click"] : ["click", "hover"],
|
||||
interactive: !requiresClick,
|
||||
delayHide: 200
|
||||
});
|
||||
|
||||
if (!children || Array.isArray(children) && !children.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<>
|
||||
<div ref={setTriggerRef} className="truncate">
|
||||
<div
|
||||
ref={setTriggerRef}
|
||||
className="truncate"
|
||||
onClick={(e) => {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
e.nativeEvent.stopImmediatePropagation();
|
||||
|
||||
onLabelClick?.(e);
|
||||
}}
|
||||
>
|
||||
{label}
|
||||
</div>
|
||||
{visible && (
|
||||
<Transition
|
||||
show={visible}
|
||||
className="z-10"
|
||||
enter="transition duration-200 ease-out"
|
||||
enterFrom="opacity-0"
|
||||
enterTo="opacity-100"
|
||||
leave="transition duration-200 ease-in"
|
||||
leaveFrom="opacity-100"
|
||||
leaveTo="opacity-0"
|
||||
>
|
||||
<div
|
||||
ref={setTooltipRef}
|
||||
{...getTooltipProps({
|
||||
className: classNames(
|
||||
maxWidth,
|
||||
"rounded-md border border-gray-300 text-black text-xs shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
|
||||
"rounded-md border border-gray-300 text-black text-xs normal-case tracking-normal font-normal shadow-lg dark:text-white dark:border-gray-700 dark:shadow-2xl"
|
||||
)
|
||||
})}
|
||||
>
|
||||
|
@ -55,13 +87,13 @@ export const Tooltip = ({
|
|||
<div
|
||||
className={classNames(
|
||||
title ? "" : "rounded-t-md",
|
||||
"py-1 px-2 rounded-b-md bg-white dark:bg-gray-900"
|
||||
"whitespace-normal break-words py-1 px-2 rounded-b-md bg-white dark:bg-gray-900"
|
||||
)}
|
||||
>
|
||||
{children}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Transition>
|
||||
</>
|
||||
);
|
||||
};
|
||||
};
|
||||
|
|
|
@ -26,6 +26,7 @@ import {
|
|||
} from "@components/inputs";
|
||||
import { clientKeys } from "@screens/settings/DownloadClient";
|
||||
import { SelectFieldWide } from "@components/inputs/input_wide";
|
||||
import { DocsLink, ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
interface InitialValuesSettings {
|
||||
basic?: {
|
||||
|
@ -54,7 +55,6 @@ interface InitialValues {
|
|||
settings: InitialValuesSettings;
|
||||
}
|
||||
|
||||
|
||||
function FormFieldsDeluge() {
|
||||
const {
|
||||
values: { tls }
|
||||
|
@ -63,11 +63,20 @@ function FormFieldsDeluge() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port"
|
||||
tooltip={<div><p>See guides for how to connect to Deluge for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated#deluge' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#deluge</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#deluge' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes#deluge</a></div>}
|
||||
required={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See guides for how to connect to Deluge for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#deluge" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#deluge" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<NumberFieldWide
|
||||
|
@ -99,14 +108,23 @@ function FormFieldsArr() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 mb-4 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Full url http(s)://domain.ltd and/or subdomain/subfolder"
|
||||
tooltip={<div><p>See guides for how to connect to the *arr suite for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated/#sonarr' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated/</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#sonarr' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes</a></div>}
|
||||
required={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See guides for how to connect to the *arr suite for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated/#sonarr" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#sonarr" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<PasswordFieldWide name="settings.apikey" label="API key" required={true}/>
|
||||
<PasswordFieldWide required name="settings.apikey" label="API key" />
|
||||
|
||||
<SwitchGroupWide name="settings.basic.auth" label="Basic auth" />
|
||||
|
||||
|
@ -130,11 +148,20 @@ function FormFieldsQbit() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Eg. http(s)://client.domain.ltd, http(s)://domain.ltd/qbittorrent, http://domain.ltd:port"
|
||||
tooltip={<div><p>See guides for how to connect to qBittorrent for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated#qbittorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#qbittorrent</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent</a></div>}
|
||||
required={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See guides for how to connect to qBittorrent for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#qbittorrent" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{port > 0 && (
|
||||
|
@ -177,16 +204,15 @@ function FormFieldsPorla() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Eg. http(s)://client.domain.ltd, http(s)://domain.ltd/porla, http://domain.ltd:port"
|
||||
required={true}
|
||||
/>
|
||||
|
||||
|
||||
<SwitchGroupWide name="tls" label="TLS" />
|
||||
|
||||
<PasswordFieldWide name="settings.apikey" label="Auth token" required={true}/>
|
||||
<PasswordFieldWide required name="settings.apikey" label="Auth token" />
|
||||
|
||||
{tls && (
|
||||
<SwitchGroupWide
|
||||
|
@ -215,11 +241,20 @@ function FormFieldsRTorrent() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Eg. http(s)://client.domain.ltd/RPC2, http(s)://domain.ltd/client, http(s)://domain.ltd/RPC2"
|
||||
tooltip={<div><p>See guides for how to connect to rTorrent for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated#rtorrent--rutorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#rtorrent--rutorrent</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#rtorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes#rtorrent</a></div>}
|
||||
required={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See guides for how to connect to rTorrent for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#rtorrent--rutorrent" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#rtorrent" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<SwitchGroupWide name="tls" label="TLS" />
|
||||
|
@ -251,11 +286,20 @@ function FormFieldsTransmission() {
|
|||
return (
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide
|
||||
required
|
||||
name="host"
|
||||
label="Host"
|
||||
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd"
|
||||
tooltip={<div><p>See guides for how to connect to Transmission for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated#transmission' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#transmission</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#transmisison' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes#transmisison</a></div>}
|
||||
required={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See guides for how to connect to Transmission for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#transmission" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#transmisison" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<NumberFieldWide name="port" label="Port" help="Port for Transmission" />
|
||||
|
@ -286,7 +330,16 @@ function FormFieldsSabnzbd() {
|
|||
name="host"
|
||||
label="Host"
|
||||
help="Eg. http://ip:port or https://url.com/sabnzbd"
|
||||
// tooltip={<div><p>See guides for how to connect to qBittorrent for various server types in our docs.</p><br /><p>Dedicated servers:</p><a href='https://autobrr.com/configuration/download-clients/dedicated#qbittorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#qbittorrent</a><p>Shared seedbox providers:</p><a href='https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent</a></div>}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See our guides on how to connect to qBittorrent for various server types in our docs.</p>
|
||||
<br />
|
||||
<p>Dedicated servers:</p>
|
||||
<ExternalLink href="https://autobrr.com/configuration/download-clients/dedicated#qbittorrent" />
|
||||
<p>Shared seedbox providers:</p>
|
||||
<ExternalLink href="https://autobrr.com/configuration/download-clients/shared-seedboxes#qbittorrent" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{port > 0 && (
|
||||
|
@ -357,10 +410,22 @@ function FormFieldsRulesBasic() {
|
|||
</p>
|
||||
</div>
|
||||
|
||||
<SwitchGroupWide name="settings.rules.enabled" label="Enabled"/>
|
||||
<SwitchGroupWide name="settings.rules.enabled" label="Enabled" />
|
||||
|
||||
{settings && settings.rules?.enabled === true && (
|
||||
<NumberFieldWide name="settings.rules.max_active_downloads" label="Max active downloads" tooltip={<span><p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p><a href='https://autobrr.com/configuration/download-clients/dedicated#deluge-rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#deluge-rules</a><br /><br /><p>See recommendations for various server types here:</p><a href='https://autobrr.com/filters/examples#build-buffer' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/examples#build-buffer</a></span>} />
|
||||
<NumberFieldWide
|
||||
name="settings.rules.max_active_downloads"
|
||||
label="Max active downloads"
|
||||
tooltip={
|
||||
<span>
|
||||
<p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#deluge-rules" />
|
||||
<br /><br />
|
||||
<p>See recommendations for various server types here:</p>
|
||||
<DocsLink href='https://autobrr.com/filters/examples#build-buffer' />
|
||||
</span>
|
||||
}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
|
@ -389,7 +454,16 @@ function FormFieldsRulesQbit() {
|
|||
<NumberFieldWide
|
||||
name="settings.rules.max_active_downloads"
|
||||
label="Max active downloads"
|
||||
tooltip={<><p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p><a href='https://autobrr.com/configuration/download-clients/dedicated#qbittorrent-rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#qbittorrent-rules</a><br /><br /><p>See recommendations for various server types here:</p><a href='https://autobrr.com/filters/examples#build-buffer' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/examples#build-buffer</a></>} />
|
||||
tooltip={
|
||||
<>
|
||||
<p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#qbittorrent-rules" />
|
||||
<br /><br />
|
||||
<p>See recommendations for various server types here:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/examples#build-buffer" />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
<SwitchGroupWide
|
||||
name="settings.rules.ignore_slow_torrents"
|
||||
label="Ignore slow torrents"
|
||||
|
@ -447,7 +521,15 @@ function FormFieldsRulesTransmission() {
|
|||
<NumberFieldWide
|
||||
name="settings.rules.max_active_downloads"
|
||||
label="Max active downloads"
|
||||
tooltip={<><p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p><a href='https://autobrr.com/configuration/download-clients/dedicated#transmission-rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/download-clients/dedicated#transmission-rules</a><br /><br /><p>See recommendations for various server types here:</p><a href='https://autobrr.com/filters/examples#build-buffer' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/examples#build-buffer</a></>}
|
||||
tooltip={
|
||||
<>
|
||||
<p>Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/download-clients/dedicated#transmission-rules" />
|
||||
<br /><br />
|
||||
<p>See recommendations for various server types here:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/examples#build-buffer" />
|
||||
</>
|
||||
}
|
||||
/>
|
||||
</>
|
||||
)}
|
||||
|
@ -456,11 +538,11 @@ function FormFieldsRulesTransmission() {
|
|||
}
|
||||
|
||||
export const rulesComponentMap: componentMapType = {
|
||||
DELUGE_V1: <FormFieldsRulesBasic/>,
|
||||
DELUGE_V2: <FormFieldsRulesBasic/>,
|
||||
QBITTORRENT: <FormFieldsRulesQbit/>,
|
||||
PORLA: <FormFieldsRulesBasic/>,
|
||||
TRANSMISSION: <FormFieldsRulesTransmission/>
|
||||
DELUGE_V1: <FormFieldsRulesBasic />,
|
||||
DELUGE_V2: <FormFieldsRulesBasic />,
|
||||
QBITTORRENT: <FormFieldsRulesQbit />,
|
||||
PORLA: <FormFieldsRulesBasic />,
|
||||
TRANSMISSION: <FormFieldsRulesTransmission />
|
||||
};
|
||||
|
||||
interface formButtonsProps {
|
||||
|
@ -582,12 +664,12 @@ export function DownloadClientAddForm({ isOpen, toggle }: formProps) {
|
|||
mutationFn: (client: DownloadClient) => APIClient.download_clients.create(client),
|
||||
onSuccess: () => {
|
||||
queryClient.invalidateQueries({ queryKey: clientKeys.lists() });
|
||||
toast.custom((t) => <Toast type="success" body="Client was added" t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body="Client was added" t={t} />);
|
||||
|
||||
toggle();
|
||||
},
|
||||
onError: () => {
|
||||
toast.custom((t) => <Toast type="error" body="Client could not be added" t={t}/>);
|
||||
toast.custom((t) => <Toast type="error" body="Client could not be added" t={t} />);
|
||||
}
|
||||
});
|
||||
|
||||
|
@ -647,7 +729,7 @@ export function DownloadClientAddForm({ isOpen, toggle }: formProps) {
|
|||
onClose={toggle}
|
||||
>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<Dialog.Overlay className="absolute inset-0"/>
|
||||
<Dialog.Overlay className="absolute inset-0" />
|
||||
|
||||
<div className="fixed inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16">
|
||||
<Transition.Child
|
||||
|
@ -697,8 +779,8 @@ export function DownloadClientAddForm({ isOpen, toggle }: formProps) {
|
|||
</div>
|
||||
|
||||
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||
<TextFieldWide name="name" label="Name" required={true}/>
|
||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||
<TextFieldWide required name="name" label="Name" />
|
||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||
<RadioFieldsetWide
|
||||
name="type"
|
||||
legend="Type"
|
||||
|
@ -720,7 +802,7 @@ export function DownloadClientAddForm({ isOpen, toggle }: formProps) {
|
|||
values={values}
|
||||
/>
|
||||
|
||||
<DEBUG values={values}/>
|
||||
<DEBUG values={values} />
|
||||
</Form>
|
||||
)}
|
||||
</Formik>
|
||||
|
@ -756,7 +838,7 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
|||
queryClient.invalidateQueries({ queryKey: clientKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: clientKeys.detail(client.id) });
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was updated successfully`} t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was updated successfully`} t={t} />);
|
||||
toggle();
|
||||
}
|
||||
});
|
||||
|
@ -769,7 +851,7 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
|||
queryClient.invalidateQueries({ queryKey: clientKeys.lists() });
|
||||
queryClient.invalidateQueries({ queryKey: clientKeys.detail(client.id) });
|
||||
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was deleted.`} t={t}/>);
|
||||
toast.custom((t) => <Toast type="success" body={`${client.name} was deleted.`} t={t} />);
|
||||
toggleDeleteModal();
|
||||
}
|
||||
});
|
||||
|
@ -841,7 +923,7 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
|||
text="Are you sure you want to remove this download client? This action cannot be undone."
|
||||
/>
|
||||
<div className="absolute inset-0 overflow-hidden">
|
||||
<Dialog.Overlay className="absolute inset-0"/>
|
||||
<Dialog.Overlay className="absolute inset-0" />
|
||||
|
||||
<div className="fixed inset-y-0 right-0 pl-10 max-w-full flex sm:pl-16">
|
||||
<Transition.Child
|
||||
|
@ -892,8 +974,8 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
|||
</div>
|
||||
|
||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y dark:divide-gray-700">
|
||||
<TextFieldWide name="name" label="Name" required={true}/>
|
||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||
<TextFieldWide required name="name" label="Name" />
|
||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||
<RadioFieldsetWide
|
||||
name="type"
|
||||
legend="Type"
|
||||
|
@ -916,7 +998,7 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
|||
values={values}
|
||||
/>
|
||||
|
||||
<DEBUG values={values}/>
|
||||
<DEBUG values={values} />
|
||||
</Form>
|
||||
);
|
||||
}}
|
||||
|
|
|
@ -22,6 +22,7 @@ import { SelectFieldBasic, SelectFieldCreatable } from "@components/inputs/selec
|
|||
import { FeedDownloadTypeOptions } from "@domain/constants";
|
||||
import { feedKeys } from "@screens/settings/Feed";
|
||||
import { indexerKeys } from "@screens/settings/Indexer";
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
|
||||
const Input = (props: InputProps) => (
|
||||
<components.Input
|
||||
|
@ -86,13 +87,29 @@ const IrcSettingFields = (ind: IndexerDefinition, indexer: string) => {
|
|||
|
||||
{ind.irc.settings.map((f: IndexerSetting, idx: number) => {
|
||||
switch (f.type) {
|
||||
case "text":
|
||||
return <TextFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} autoComplete="off" validate={validateField(f)} tooltip={<div><p>Please read our IRC guide if you are unfamiliar with IRC.</p><a href='https://autobrr.com/configuration/irc' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/configuration/irc</a></div>} />;
|
||||
case "secret":
|
||||
if (f.name === "invite_command") {
|
||||
return <PasswordFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} defaultVisible={true} defaultValue={f.default} validate={validateField(f)} />;
|
||||
}
|
||||
return <PasswordFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} defaultValue={f.default} validate={validateField(f)} />;
|
||||
case "text":
|
||||
return (
|
||||
<TextFieldWide
|
||||
key={idx}
|
||||
name={`irc.${f.name}`}
|
||||
label={f.label}
|
||||
required={f.required}
|
||||
help={f.help}
|
||||
autoComplete="off"
|
||||
validate={validateField(f)}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Please read our IRC guide if you are unfamiliar with IRC.</p>
|
||||
<DocsLink href="https://autobrr.com/configuration/irc" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
case "secret":
|
||||
if (f.name === "invite_command") {
|
||||
return <PasswordFieldWide defaultVisible name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} defaultValue={f.default} validate={validateField(f)} />;
|
||||
}
|
||||
return <PasswordFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} defaultValue={f.default} validate={validateField(f)} />;
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
|
@ -224,7 +241,21 @@ const SettingFields = (ind: IndexerDefinition, indexer: string) => {
|
|||
);
|
||||
case "secret":
|
||||
return (
|
||||
<PasswordFieldWide name={`settings.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} validate={validateField(f)} tooltip={<div><p>This field does not take a full URL. Only use alphanumeric strings like <code>uqcdi67cibkx3an8cmdm</code>.</p><br /><a href='https://autobrr.com/faqs#common-action-rejections' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/faqs#common-action-rejections</a></div>} />
|
||||
<PasswordFieldWide
|
||||
name={`settings.${f.name}`}
|
||||
label={f.label}
|
||||
required={f.required}
|
||||
key={idx}
|
||||
help={f.help}
|
||||
validate={validateField(f)}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field does not take a full URL. Only use alphanumeric strings like <code>uqcdi67cibkx3an8cmdm</code>.</p>
|
||||
<br />
|
||||
<DocsLink href="https://autobrr.com/faqs#common-action-rejections" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
|
@ -752,14 +783,26 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
|
|||
<div key="opt">
|
||||
{settings.map((f: IndexerSetting, idx: number) => {
|
||||
switch (f.type) {
|
||||
case "text":
|
||||
return (
|
||||
<TextFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} />
|
||||
);
|
||||
case "secret":
|
||||
return (
|
||||
<PasswordFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} tooltip={<div><p>This field does not take a full URL. Only use alphanumeric strings like <code>uqcdi67cibkx3an8cmdm</code>.</p><br /><a href='https://autobrr.com/faqs#common-action-rejections' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/faqs#common-action-rejections</a></div>} />
|
||||
);
|
||||
case "text":
|
||||
return (
|
||||
<TextFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} />
|
||||
);
|
||||
case "secret":
|
||||
return (
|
||||
<PasswordFieldWide
|
||||
key={idx}
|
||||
name={`settings.${f.name}`}
|
||||
label={f.label}
|
||||
help={f.help}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field does not take a full URL. Only use alphanumeric strings like <code>uqcdi67cibkx3an8cmdm</code>.</p>
|
||||
<br />
|
||||
<DocsLink href="https://autobrr.com/faqs#common-action-rejections" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
);
|
||||
}
|
||||
return null;
|
||||
})}
|
||||
|
|
|
@ -20,6 +20,7 @@ import Toast from "@components/notifications/Toast";
|
|||
import { SlideOver } from "@components/panels";
|
||||
import { componentMapType } from "./DownloadClientForms";
|
||||
import { notificationKeys } from "@screens/settings/Notifications";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
const Input = (props: InputProps) => {
|
||||
return (
|
||||
|
@ -68,7 +69,14 @@ function FormFieldsDiscord() {
|
|||
<div className="px-4 space-y-1">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Create a <a href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks" rel="noopener noreferrer" target="_blank" className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400">webhook integration</a> in your server.
|
||||
{"Create a "}
|
||||
<ExternalLink
|
||||
href="https://support.discord.com/hc/en-us/articles/228383668-Intro-to-Webhooks"
|
||||
className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400"
|
||||
>
|
||||
webhook integration
|
||||
</ExternalLink>
|
||||
{" in your server."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -107,7 +115,14 @@ function FormFieldsTelegram() {
|
|||
<div className="px-4 space-y-1">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Read how to <a href="https://core.telegram.org/bots#3-how-do-i-create-a-bot" rel="noopener noreferrer" target="_blank" className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400">create a bot</a>.
|
||||
{"Read how to "}
|
||||
<ExternalLink
|
||||
href="https://core.telegram.org/bots#3-how-do-i-create-a-bot"
|
||||
className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400"
|
||||
>
|
||||
create a bot
|
||||
</ExternalLink>
|
||||
{"."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
@ -136,7 +151,14 @@ function FormFieldsPushover() {
|
|||
<div className="px-4 space-y-1">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
|
||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||
Register a new <a href="https://support.pushover.net/i175-how-do-i-get-an-api-or-application-token" rel="noopener noreferrer" target="_blank" className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400">application</a> and add its API Token here.
|
||||
{"Register a new "}
|
||||
<ExternalLink
|
||||
href="https://support.pushover.net/i175-how-do-i-get-an-api-or-application-token"
|
||||
className="font-medium text-blue-500 underline underline-offset-1 hover:text-blue-400"
|
||||
>
|
||||
application
|
||||
</ExternalLink>
|
||||
{" and add its API Token here."}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
|
|
@ -8,7 +8,6 @@ import { createRoot } from "react-dom/client";
|
|||
import { Buffer } from "buffer";
|
||||
|
||||
import "./index.css";
|
||||
import "react-tooltip/dist/react-tooltip.css";
|
||||
|
||||
import { App } from "./App";
|
||||
import { InitializeGlobalContext } from "./utils/Context";
|
||||
|
|
|
@ -7,6 +7,7 @@ import { useState } from "react";
|
|||
import { ChevronUpIcon, ChevronDownIcon } from "@heroicons/react/24/solid";
|
||||
|
||||
import { ReleaseTable } from "./releases/ReleaseTable";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
const Code = ({ children }: { children: React.ReactNode }) => (
|
||||
<code className="rounded-md inline-block mb-1 px-1 py-0.5 border bg-gray-100 border-gray-300 dark:bg-gray-800 dark:border-gray-700">
|
||||
|
@ -45,7 +46,7 @@ export const Releases = () => {
|
|||
<div className="flex justify-between items-center text-base font-medium pl-2 py-1 border-b border-gray-300 bg-gray-100 dark:border-gray-700 dark:bg-gray-800 rounded-t-md">
|
||||
Search tips
|
||||
</div>
|
||||
<div className={"rounded-t-md py-1 px-2 rounded-b-md bg-white dark:bg-gray-900"}>
|
||||
<div className="rounded-t-md py-1 px-2 rounded-b-md bg-white dark:bg-gray-900">
|
||||
You can use <b>2</b> special <span className="underline decoration-2 underline-offset-2 decoration-amber-500">wildcard characters</span> for the purpose of pattern matching.
|
||||
<br />
|
||||
- Percent (<Code>%</Code>) - for matching any <i>sequence</i> of characters (equivalent to <Code>*</Code> in Regex)
|
||||
|
@ -75,14 +76,14 @@ export const Releases = () => {
|
|||
|
||||
<br /><br />
|
||||
|
||||
As always, please refer to our <a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
{"As always, please refer to our "}
|
||||
<ExternalLink
|
||||
href="https://autobrr.com/usage/search/"
|
||||
className="text-gray-700 dark:text-gray-200 underline font-semibold underline-offset-2 decoration-purple-500 decoration-2 hover:text-black hover:dark:text-gray-100"
|
||||
>
|
||||
Search function usage
|
||||
</a> documentation page to keep up with the latest examples and information.
|
||||
</ExternalLink>
|
||||
{" documentation page to keep up with the latest examples and information."}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
|
|
|
@ -8,13 +8,13 @@ import { useForm } from "react-hook-form";
|
|||
import { useNavigate } from "react-router-dom";
|
||||
import { useMutation } from "@tanstack/react-query";
|
||||
import toast from "react-hot-toast";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
|
||||
import { ReactComponent as Logo } from "@app/logo.svg";
|
||||
import { APIClient } from "@api/APIClient";
|
||||
import { AuthContext } from "@utils/Context";
|
||||
import { PasswordInput, TextInput } from "@components/inputs/text";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
import { PasswordInput, TextInput } from "@components/inputs/text";
|
||||
|
||||
type LoginFormFields = {
|
||||
username: string;
|
||||
|
@ -103,8 +103,15 @@ export const Login = () => {
|
|||
</button>
|
||||
<div>
|
||||
<span className="flex float-right items-center mt-3 text-xs font-bold text-gray-700 dark:text-gray-200 uppercase tracking-wide cursor-pointer" id="forgot">
|
||||
Forgot?<svg className="ml-1 w-3 h-3 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10"/></svg>
|
||||
<Tooltip style={{ maxWidth: "350px", fontSize: "12px", textTransform: "none", fontWeight: "normal", borderRadius: "0.375rem", backgroundColor: "#34343A", color: "#fff", opacity: "1" }} place="bottom" delayShow={100} delayHide={150} anchorId="forgot" html="<p style='padding-top: 2px'>If you forget your password you can reset it via the terminal: <code>autobrrctl --config /home/username/.config/autobrr change-password <USERNAME></code></p>" clickable={true}/>
|
||||
<Tooltip
|
||||
label={
|
||||
<div className="flex flex-row items-center">
|
||||
Forgot? <svg className="ml-1 w-3 h-3 text-gray-500 dark:text-gray-400 fill-current" viewBox="0 0 72 72"><path d="M32 2C15.432 2 2 15.432 2 32s13.432 30 30 30s30-13.432 30-30S48.568 2 32 2m5 49.75H27v-24h10v24m-5-29.5a5 5 0 1 1 0-10a5 5 0 0 1 0 10"/></svg>
|
||||
</div>
|
||||
}
|
||||
>
|
||||
<p className="py-1">If you forget your password you can reset it via the terminal: <code>autobrrctl --config /home/username/.config/autobrr change-password $USERNAME</code></p>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -28,6 +28,7 @@ import { DeleteModal } from "@components/modals";
|
|||
import { CollapsableSection } from "./Details";
|
||||
import { TextArea } from "@components/inputs/input";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
|
||||
interface FilterActionsProps {
|
||||
filter: Filter;
|
||||
|
@ -224,7 +225,15 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
|
|||
label="Save path"
|
||||
columns={6}
|
||||
placeholder="eg. /full/path/to/download_folder"
|
||||
tooltip={<div><p>Set a custom save path for this action. Automatic Torrent Management will take care of this if using qBittorrent with categories.</p><br /><p>The field can use macros to transform/add values from metadata:</p><a href='https://autobrr.com/filters/actions#macros' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/actions#macros</a></div>} />
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Set a custom save path for this action. Automatic Torrent Management will take care of this if using qBittorrent with categories.</p>
|
||||
<br />
|
||||
<p>The field can use macros to transform/add values from metadata:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/actions#macros" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -234,13 +243,25 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
|
|||
label="Category"
|
||||
columns={6}
|
||||
placeholder="eg. category"
|
||||
tooltip={<div><p>The field can use macros to transform/add values from metadata:</p><a href='https://autobrr.com/filters/actions#macros' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/actions#macros</a></div>} />
|
||||
tooltip={
|
||||
<div>
|
||||
<p>The field can use macros to transform/add values from metadata:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/actions#macros" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
name={`actions.${idx}.tags`}
|
||||
label="Tags"
|
||||
columns={6}
|
||||
placeholder="eg. tag1,tag2"
|
||||
tooltip={<div><p>The field can use macros to transform/add values from metadata:</p><a href='https://autobrr.com/filters/actions#macros' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/actions#macros</a></div>} />
|
||||
tooltip={
|
||||
<div>
|
||||
<p>The field can use macros to transform/add values from metadata:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/actions#macros" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<CollapsableSection title="Rules" subtitle="client options">
|
||||
|
@ -282,7 +303,14 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
|
|||
<SwitchGroup
|
||||
name={`actions.${idx}.ignore_rules`}
|
||||
label="Ignore client rules"
|
||||
tooltip={<div><p>Choose to ignore rules set in <Link className='text-blue-400 visited:text-blue-400' to="/settings/clients">Client Settings</Link>.</p></div>} />
|
||||
tooltip={
|
||||
<div>
|
||||
<p>
|
||||
Choose to ignore rules set in <Link className="text-blue-400 visited:text-blue-400" to="/settings/clients">Client Settings</Link>.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="col-span-6">
|
||||
<Select
|
||||
|
|
|
@ -51,6 +51,7 @@ import { FilterActions } from "./Action";
|
|||
import { filterKeys } from "./List";
|
||||
import { External } from "@screens/filters/External";
|
||||
import { SectionLoader } from "@components/SectionLoader";
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
|
||||
interface tabType {
|
||||
name: string;
|
||||
|
@ -458,12 +459,75 @@ export function General() {
|
|||
<TitleSubtitle title="Rules" subtitle="Specify rules on how torrents should be handled/selected." />
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<TextField name="min_size" label="Min size" columns={6} placeholder="eg. 100MiB, 80GB" tooltip={<div><p>Supports units such as MB, MiB, GB, etc.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<TextField name="max_size" label="Max size" columns={6} placeholder="eg. 100MiB, 80GB" tooltip={<div><p>Supports units such as MB, MiB, GB, etc.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<NumberField name="delay" label="Delay" placeholder="Number of seconds to delay actions" tooltip={<div><p>Number of seconds to wait before running actions.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<NumberField name="priority" label="Priority" placeholder="Higher number = higher prio" tooltip={<div><p>Filters are checked in order of priority. Higher number = higher priority.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<NumberField name="max_downloads" label="Max downloads" placeholder="Takes any number (0 is infinite)" tooltip={<div><p>Number of max downloads as specified by the respective unit.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<Select name="max_downloads_unit" label="Max downloads per" options={downloadsPerUnitOptions} optionDefaultText="Select unit" tooltip={<div><p>The unit of time for counting the maximum downloads per filter.</p><a href='https://autobrr.com/filters#rules' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#rules</a></div>} />
|
||||
<TextField
|
||||
name="min_size"
|
||||
label="Min size"
|
||||
columns={6}
|
||||
placeholder="eg. 100MiB, 80GB"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Supports units such as MB, MiB, GB, etc.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
name="max_size"
|
||||
label="Max size"
|
||||
columns={6}
|
||||
placeholder="eg. 100MiB, 80GB"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Supports units such as MB, MiB, GB, etc.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<NumberField
|
||||
name="delay"
|
||||
label="Delay"
|
||||
placeholder="Number of seconds to delay actions"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Number of seconds to wait before running actions.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<NumberField
|
||||
name="priority"
|
||||
label="Priority"
|
||||
placeholder="Higher number = higher priority"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Filters are checked in order of priority. Higher number = higher priority.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<NumberField
|
||||
name="max_downloads"
|
||||
label="Max downloads"
|
||||
placeholder="Takes any number (0 is infinite)"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Number of max downloads as specified by the respective unit.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Select
|
||||
name="max_downloads_unit"
|
||||
label="Max downloads per"
|
||||
options={downloadsPerUnitOptions}
|
||||
optionDefaultText="Select unit"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>The unit of time for counting the maximum downloads per filter.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#rules" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -478,43 +542,194 @@ export function MoviesTv() {
|
|||
return (
|
||||
<div>
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<TextAreaAutoResize name="shows" label="Movies / Shows" columns={8} placeholder="eg. Movie,Show 1,Show?2" tooltip={<div><p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p><a href='https://autobrr.com/filters#tvmovies' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#tvmovies</a></div>} />
|
||||
<TextField name="years" label="Years" columns={4} placeholder="eg. 2018,2019-2021" tooltip={<div><p>This field takes a range of years and/or comma separated single years.</p><a href='https://autobrr.com/filters#tvmovies' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#tvmovies</a></div>} />
|
||||
<TextAreaAutoResize
|
||||
name="shows"
|
||||
label="Movies / Shows"
|
||||
columns={8}
|
||||
placeholder="eg. Movie,Show 1,Show?2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p>
|
||||
<DocsLink href="https://autobrr.com/filters#tvmovies" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
name="years"
|
||||
label="Years"
|
||||
columns={4}
|
||||
placeholder="eg. 2018,2019-2021"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field takes a range of years and/or comma separated single years.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#tvmovies" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="mt-6 lg:pb-8">
|
||||
<TitleSubtitle title="Seasons and Episodes" subtitle="Set season and episode match constraints." />
|
||||
<TitleSubtitle
|
||||
title="Seasons and Episodes"
|
||||
subtitle="Set season and episode match constraints."
|
||||
/>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<TextField name="seasons" label="Seasons" columns={8} placeholder="eg. 1,3,2-6" tooltip={<div><p>See docs for information about how to <b>only</b> grab season packs:</p><a href='https://autobrr.com/filters/examples#only-season-packs' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/examples#only-season-packs</a></div>} />
|
||||
<TextField name="episodes" label="Episodes" columns={4} placeholder="eg. 2,4,10-20" tooltip={<div><p>See docs for information about how to <b>only</b> grab episodes:</p><a href='https://autobrr.com/filters/examples/#skip-season-packs' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/examples/#skip-season-packs</a></div>} />
|
||||
<TextField
|
||||
name="seasons"
|
||||
label="Seasons"
|
||||
columns={8}
|
||||
placeholder="eg. 1,3,2-6"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See docs for information about how to <b>only</b> grab season packs:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/examples#only-season-packs" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
name="episodes"
|
||||
label="Episodes"
|
||||
columns={4}
|
||||
placeholder="eg. 2,4,10-20"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>See docs for information about how to <b>only</b> grab episodes:</p>
|
||||
<DocsLink href="https://autobrr.com/filters/examples/#skip-season-packs" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6">
|
||||
<CheckboxField name="smart_episode" label="Smart Episode" sublabel="Do not match episodes older than the last one matched." /> {/*Do not match older or already existing episodes.*/}
|
||||
<CheckboxField
|
||||
name="smart_episode"
|
||||
label="Smart Episode"
|
||||
sublabel="Do not match episodes older than the last one matched."
|
||||
/>{" "}
|
||||
{/*Do not match older or already existing episodes.*/}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 lg:pb-8">
|
||||
<TitleSubtitle title="Quality" subtitle="Set resolution, source, codec and related match constraints." />
|
||||
<TitleSubtitle
|
||||
title="Quality"
|
||||
subtitle="Set resolution, source, codec and related match constraints."
|
||||
/>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="resolutions" options={RESOLUTION_OPTIONS} label="resolutions" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected resolutions.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect name="sources" options={SOURCES_OPTIONS} label="sources" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected sources.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect
|
||||
name="resolutions"
|
||||
options={RESOLUTION_OPTIONS}
|
||||
label="resolutions"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected resolutions.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="sources"
|
||||
options={SOURCES_OPTIONS}
|
||||
label="sources"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected sources.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="codecs" options={CODECS_OPTIONS} label="codecs" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected codecs.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect name="containers" options={CONTAINER_OPTIONS} label="containers" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected containers.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect
|
||||
name="codecs"
|
||||
options={CODECS_OPTIONS}
|
||||
label="codecs"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected codecs.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="containers"
|
||||
options={CONTAINER_OPTIONS}
|
||||
label="containers"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected containers.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="match_hdr" options={HDR_OPTIONS} label="Match HDR" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected HDR designations.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect name="except_hdr" options={HDR_OPTIONS} label="Except HDR" columns={6} creatable={true} tooltip={<div><p>Won't match releases which contain any of the selected HDR designations (takes priority over Match HDR).</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect
|
||||
name="match_hdr"
|
||||
options={HDR_OPTIONS}
|
||||
label="Match HDR"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected HDR designations.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="except_hdr"
|
||||
options={HDR_OPTIONS}
|
||||
label="Except HDR"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Won't match releases which contain any of the selected HDR designations (takes priority over Match HDR).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="match_other" options={OTHER_OPTIONS} label="Match Other" columns={6} creatable={true} tooltip={<div><p>Will match releases which contain any of the selected designations.</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect name="except_other" options={OTHER_OPTIONS} label="Except Other" columns={6} creatable={true} tooltip={<div><p>Won't match releases which contain any of the selected Other designations (takes priority over Match Other).</p><a href='https://autobrr.com/filters#quality' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality</a></div>} />
|
||||
<MultiSelect
|
||||
name="match_other"
|
||||
options={OTHER_OPTIONS}
|
||||
label="Match Other"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will match releases which contain any of the selected designations.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="except_other"
|
||||
options={OTHER_OPTIONS}
|
||||
label="Except Other"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Won't match releases which contain any of the selected Other designations (takes priority over Match Other).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -525,47 +740,147 @@ export function Music({ values }: AdvancedProps) {
|
|||
return (
|
||||
<div>
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<TextAreaAutoResize name="artists" label="Artists" columns={4} placeholder="eg. Artist One" tooltip={<div><p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p><a href='https://autobrr.com/filters#music' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#music</a></div>} />
|
||||
<TextAreaAutoResize name="albums" label="Albums" columns={4} placeholder="eg. That Album" tooltip={<div><p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p><a href='https://autobrr.com/filters#music' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#music</a></div>} />
|
||||
<TextField name="years" label="Years" columns={4} placeholder="eg. 2018,2019-2021" tooltip={<div><p>This field takes a range of years and/or comma separated single years.</p><a href='https://autobrr.com/filters#music' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#music</a></div>} />
|
||||
<TextAreaAutoResize
|
||||
name="artists"
|
||||
label="Artists"
|
||||
columns={4}
|
||||
placeholder="eg. Artist One"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p>
|
||||
<DocsLink href="https://autobrr.com/filters#music" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextAreaAutoResize
|
||||
name="albums"
|
||||
label="Albums"
|
||||
columns={4}
|
||||
placeholder="eg. That Album"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>You can use basic filtering like wildcards <code>*</code> or replace single characters with <code>?</code></p>
|
||||
<DocsLink href="https://autobrr.com/filters#music" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextField
|
||||
name="years"
|
||||
label="Years"
|
||||
columns={4}
|
||||
placeholder="eg. 2018,2019-2021"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field takes a range of years and/or comma separated single years.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#music" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 lg:pb-8">
|
||||
<TitleSubtitle title="Quality" subtitle="Format, source, log etc." />
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="formats" options={FORMATS_OPTIONS} label="Format" columns={6} disabled={values.perfect_flac} tooltip={<div><p> Will only match releases with any of the selected formats. This is overridden by Perfect FLAC.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
<MultiSelect name="quality" options={QUALITY_MUSIC_OPTIONS} label="Quality" columns={6} disabled={values.perfect_flac} tooltip={<div><p> Will only match releases with any of the selected qualities. This is overridden by Perfect FLAC.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect name="media" options={SOURCES_MUSIC_OPTIONS} label="Media" columns={6} disabled={values.perfect_flac} tooltip={<div><p> Will only match releases with any of the selected sources. This is overridden by Perfect FLAC.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
<MultiSelect name="match_release_types" options={RELEASE_TYPE_MUSIC_OPTIONS} label="Type" columns={6} tooltip={<div><p> Will only match releases with any of the selected types.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<NumberField name="log_score" label="Log score" placeholder="eg. 100" min={0} max={100} disabled={values.perfect_flac} tooltip={<div><p> Log scores go from 0 to 100. This is overridden by Perfect FLAC.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div className="space-y-6 sm:space-y-5 divide-y divide-gray-200">
|
||||
<div className="pt-6 sm:pt-5">
|
||||
<div role="group" aria-labelledby="label-email">
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
{/* <div>
|
||||
<div className="text-base font-medium text-gray-900 sm:text-sm sm:text-gray-700" >
|
||||
Extra
|
||||
</div>
|
||||
</div> */}
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg space-y-4">
|
||||
<CheckboxField name="log" label="Log" sublabel="Must include Log." disabled={values.perfect_flac} />
|
||||
<CheckboxField name="cue" label="Cue" sublabel="Must include Cue." disabled={values.perfect_flac} />
|
||||
<CheckboxField name="perfect_flac" label="Perfect FLAC" sublabel="Override all options about quality, source, format, and cue/log/log score." tooltip={<div><p>Override all options about quality, source, format, and cue/log/log score.</p><a href='https://autobrr.com/filters#quality-1' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#quality-1</a></div>} />
|
||||
</div>
|
||||
<MultiSelect
|
||||
name="formats"
|
||||
options={FORMATS_OPTIONS}
|
||||
label="Format"
|
||||
columns={6}
|
||||
disabled={values.perfect_flac}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will only match releases with any of the selected formats. This is overridden by Perfect FLAC.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="quality"
|
||||
options={QUALITY_MUSIC_OPTIONS}
|
||||
label="Quality"
|
||||
columns={6}
|
||||
disabled={values.perfect_flac}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will only match releases with any of the selected qualities. This is overridden by Perfect FLAC.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<MultiSelect
|
||||
name="media"
|
||||
options={SOURCES_MUSIC_OPTIONS}
|
||||
label="Media"
|
||||
columns={6}
|
||||
disabled={values.perfect_flac}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will only match releases with any of the selected sources. This is overridden by Perfect FLAC.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="match_release_types"
|
||||
options={RELEASE_TYPE_MUSIC_OPTIONS}
|
||||
label="Type"
|
||||
columns={6}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Will only match releases with any of the selected types.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||
<NumberField
|
||||
name="log_score"
|
||||
label="Log score"
|
||||
placeholder="eg. 100"
|
||||
min={0}
|
||||
max={100}
|
||||
disabled={values.perfect_flac}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Log scores go from 0 to 100. This is overridden by Perfect FLAC.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="sm:grid sm:grid-cols-3 sm:gap-4 sm:items-baseline">
|
||||
<div className="mt-4 sm:mt-0 sm:col-span-2">
|
||||
<div className="max-w-lg space-y-4">
|
||||
<CheckboxField
|
||||
name="log"
|
||||
label="Log"
|
||||
sublabel="Must include Log."
|
||||
disabled={values.perfect_flac}
|
||||
/>
|
||||
<CheckboxField
|
||||
name="cue"
|
||||
label="Cue"
|
||||
sublabel="Must include Cue."
|
||||
disabled={values.perfect_flac}
|
||||
/>
|
||||
<CheckboxField
|
||||
name="perfect_flac"
|
||||
label="Perfect FLAC"
|
||||
sublabel="Override all options about quality, source, format, and cue/log/log score."
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Override all options about quality, source, format, and cue/log/log score.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#quality-1" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -580,18 +895,54 @@ interface AdvancedProps {
|
|||
export function Advanced({ values }: AdvancedProps) {
|
||||
return (
|
||||
<div>
|
||||
<CollapsableSection defaultOpen={true} title="Releases" subtitle="Match only certain release names and/or ignore other release names.">
|
||||
<CollapsableSection
|
||||
defaultOpen
|
||||
title="Releases"
|
||||
subtitle="Match only certain release names and/or ignore other release names."
|
||||
>
|
||||
<div className="grid col-span-12 gap-6">
|
||||
<WarningAlert text="autobrr has extensive filtering built-in - only use this if nothing else works. If you need help, please ask." />
|
||||
|
||||
<RegexTextAreaField name="match_releases" label="Match releases" useRegex={values.use_regex} columns={6} placeholder="eg. *some?movie*,*some?show*s01*" tooltip={<div><p>This field has full regex support (Golang flavour).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a><br /><br /><p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p></div>} />
|
||||
<RegexTextAreaField name="except_releases" label="Except releases" useRegex={values.use_regex} columns={6} placeholder="eg. *bad?movie*,*bad?show*s03*" tooltip={<div><p>This field has full regex support (Golang flavour).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a><br /><br /><p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p></div>} />
|
||||
<RegexTextAreaField
|
||||
name="match_releases"
|
||||
label="Match releases"
|
||||
useRegex={values.use_regex}
|
||||
columns={6}
|
||||
placeholder="eg. *some?movie*,*some?show*s01*"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field has full regex support (Golang flavour).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
<br />
|
||||
<br />
|
||||
<p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<RegexTextAreaField
|
||||
name="except_releases"
|
||||
label="Except releases"
|
||||
useRegex={values.use_regex}
|
||||
columns={6}
|
||||
placeholder="eg. *bad?movie*,*bad?show*s03*"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field has full regex support (Golang flavour).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
<br />
|
||||
<br />
|
||||
<p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
{values.match_releases ? (
|
||||
<WarningAlert
|
||||
alert="Ask yourself:"
|
||||
text={
|
||||
<>Do you have a good reason to use <strong>Match releases</strong> instead of one of the other tabs?</>
|
||||
<>
|
||||
Do you have a good reason to use <strong>Match releases</strong> instead of one of the other tabs?
|
||||
</>
|
||||
}
|
||||
colors="text-cyan-700 bg-cyan-100 dark:bg-cyan-200 dark:text-cyan-800"
|
||||
/>
|
||||
|
@ -600,7 +951,9 @@ export function Advanced({ values }: AdvancedProps) {
|
|||
<WarningAlert
|
||||
alert="Ask yourself:"
|
||||
text={
|
||||
<>Do you have a good reason to use <strong>Except releases</strong> instead of one of the other tabs?</>
|
||||
<>
|
||||
Do you have a good reason to use <strong>Except releases</strong> instead of one of the other tabs?
|
||||
</>
|
||||
}
|
||||
colors="text-fuchsia-700 bg-fuchsia-100 dark:bg-fuchsia-200 dark:text-fuchsia-800"
|
||||
/>
|
||||
|
@ -611,42 +964,215 @@ export function Advanced({ values }: AdvancedProps) {
|
|||
</div>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Groups" subtitle="Match only certain groups and/or ignore other groups.">
|
||||
<TextAreaAutoResize name="match_release_groups" label="Match release groups" columns={6} placeholder="eg. group1,group2" tooltip={<div><p>Comma separated list of release groups to match.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<TextAreaAutoResize name="except_release_groups" label="Except release groups" columns={6} placeholder="eg. badgroup1,badgroup2" tooltip={<div><p>Comma separated list of release groups to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Groups"
|
||||
subtitle="Match only certain groups and/or ignore other groups."
|
||||
>
|
||||
<TextAreaAutoResize
|
||||
name="match_release_groups"
|
||||
label="Match release groups"
|
||||
columns={6}
|
||||
placeholder="eg. group1,group2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of release groups to match.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextAreaAutoResize
|
||||
name="except_release_groups"
|
||||
label="Except release groups"
|
||||
columns={6}
|
||||
placeholder="eg. badgroup1,badgroup2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of release groups to ignore (takes priority over Match releases).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Categories and tags" subtitle="Match or ignore categories or tags.">
|
||||
<TextAreaAutoResize name="match_categories" label="Match categories" columns={6} placeholder="eg. *category*,category1" tooltip={<div><p>Comma separated list of categories to match.</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
||||
<TextAreaAutoResize name="except_categories" label="Except categories" columns={6} placeholder="eg. *category*" tooltip={<div><p>Comma separated list of categories to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters/categories' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/categories</a></div>} />
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Categories and tags"
|
||||
subtitle="Match or ignore categories or tags."
|
||||
>
|
||||
<TextAreaAutoResize
|
||||
name="match_categories"
|
||||
label="Match categories"
|
||||
columns={6}
|
||||
placeholder="eg. *category*,category1"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of categories to match.</p>
|
||||
<DocsLink href="https://autobrr.com/filters/categories" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextAreaAutoResize
|
||||
name="except_categories"
|
||||
label="Except categories"
|
||||
columns={6}
|
||||
placeholder="eg. *category*"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of categories to ignore (takes priority over Match releases).</p>
|
||||
<DocsLink href="https://autobrr.com/filters/categories" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
||||
<TextAreaAutoResize name="tags" label="Match tags" columns={4} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to match.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<Select name="tags_match_logic" label="Tags logic" columns={2} options={tagsMatchLogicOptions} optionDefaultText="any" tooltip={<div><p>Logic used to match filter tags.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<TextAreaAutoResize name="except_tags" label="Except tags" columns={4} placeholder="eg. tag1,tag2" tooltip={<div><p>Comma separated list of tags to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>hhttps://autobrr.com/filters#advanced</a></div>} />
|
||||
<Select name="except_tags_match_logic" label="Except tags logic" columns={2} options={tagsMatchLogicOptions} optionDefaultText="any" tooltip={<div><p>Logic used to match except tags.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<TextAreaAutoResize
|
||||
name="tags"
|
||||
label="Match tags"
|
||||
columns={4}
|
||||
placeholder="eg. tag1,tag2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of tags to match.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Select
|
||||
name="tags_match_logic"
|
||||
label="Tags logic"
|
||||
columns={2}
|
||||
options={tagsMatchLogicOptions}
|
||||
optionDefaultText="any"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Logic used to match filter tags.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextAreaAutoResize
|
||||
name="except_tags"
|
||||
label="Except tags"
|
||||
columns={4}
|
||||
placeholder="eg. tag1,tag2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of tags to ignore (takes priority over Match releases).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<Select
|
||||
name="except_tags_match_logic"
|
||||
label="Except tags logic"
|
||||
columns={2}
|
||||
options={tagsMatchLogicOptions}
|
||||
optionDefaultText="any"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Logic used to match except tags.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Uploaders" subtitle="Match or ignore uploaders.">
|
||||
<TextAreaAutoResize name="match_uploaders" label="Match uploaders" columns={6} placeholder="eg. uploader1,uploader2" tooltip={<div><p>Comma separated list of uploaders to match.</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<TextAreaAutoResize name="except_uploaders" label="Except uploaders" columns={6} placeholder="eg. anonymous1,anonymous2" tooltip={<div><p>Comma separated list of uploaders to ignore (takes priority over Match releases).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a></div>} />
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Uploaders"
|
||||
subtitle="Match or ignore uploaders."
|
||||
>
|
||||
<TextAreaAutoResize
|
||||
name="match_uploaders"
|
||||
label="Match uploaders"
|
||||
columns={6}
|
||||
placeholder="eg. uploader1,uploader2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of uploaders to match.</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<TextAreaAutoResize
|
||||
name="except_uploaders"
|
||||
label="Except uploaders"
|
||||
columns={6}
|
||||
placeholder="eg. anonymous1,anonymous2"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>Comma separated list of uploaders to ignore (takes priority over Match releases).
|
||||
</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Language" subtitle="Match or ignore languages.">
|
||||
<MultiSelect name="match_language" options={LANGUAGE_OPTIONS} label="Match Language" columns={6} creatable={true} />
|
||||
<MultiSelect name="except_language" options={LANGUAGE_OPTIONS} label="Except Language" columns={6} creatable={true} />
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Language"
|
||||
subtitle="Match or ignore languages."
|
||||
>
|
||||
<MultiSelect
|
||||
name="match_language"
|
||||
options={LANGUAGE_OPTIONS}
|
||||
label="Match Language"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="except_language"
|
||||
options={LANGUAGE_OPTIONS}
|
||||
label="Except Language"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
/>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Origins" subtitle="Match Internals, scene, p2p etc. if announced.">
|
||||
<MultiSelect name="origins" options={ORIGIN_OPTIONS} label="Match Origins" columns={6} creatable={true} />
|
||||
<MultiSelect name="except_origins" options={ORIGIN_OPTIONS} label="Except Origins" columns={6} creatable={true} />
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Origins"
|
||||
subtitle="Match Internals, scene, p2p etc. if announced."
|
||||
>
|
||||
<MultiSelect
|
||||
name="origins"
|
||||
options={ORIGIN_OPTIONS}
|
||||
label="Match Origins"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
/>
|
||||
<MultiSelect
|
||||
name="except_origins"
|
||||
options={ORIGIN_OPTIONS}
|
||||
label="Except Origins"
|
||||
columns={6}
|
||||
creatable={true}
|
||||
/>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Release Tags" subtitle="This is the non-parsed releaseTags string from the announce.">
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Release Tags"
|
||||
subtitle="This is the non-parsed releaseTags string from the announce."
|
||||
>
|
||||
<div className="grid col-span-12 gap-6">
|
||||
<WarningAlert text="These might not be what you think they are. For advanced users who know how things are parsed." />
|
||||
|
||||
<RegexField name="match_release_tags" label="Match release tags" useRegex={values.use_regex_release_tags} columns={6} placeholder="eg. *mkv*,*foreign*" />
|
||||
<RegexField name="except_release_tags" label="Except release tags" useRegex={values.use_regex_release_tags} columns={6} placeholder="eg. *mkv*,*foreign*" />
|
||||
<RegexField
|
||||
name="match_release_tags"
|
||||
label="Match release tags"
|
||||
useRegex={values.use_regex_release_tags}
|
||||
columns={6}
|
||||
placeholder="eg. *mkv*,*foreign*"
|
||||
/>
|
||||
<RegexField
|
||||
name="except_release_tags"
|
||||
label="Except release tags"
|
||||
useRegex={values.use_regex_release_tags}
|
||||
columns={6}
|
||||
placeholder="eg. *mkv*,*foreign*"
|
||||
/>
|
||||
|
||||
<div className="col-span-6">
|
||||
<SwitchGroup name="use_regex_release_tags" label="Use Regex" />
|
||||
|
@ -654,10 +1180,44 @@ export function Advanced({ values }: AdvancedProps) {
|
|||
</div>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Feeds" subtitle="These options are only for Feeds such as RSS, Torznab and Newznab">
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Feeds"
|
||||
subtitle="These options are only for Feeds such as RSS, Torznab and Newznab"
|
||||
>
|
||||
{/*<div className="grid col-span-12 gap-6">*/}
|
||||
<RegexTextAreaField name="match_description" label="Match description" useRegex={values.use_regex_description} columns={6} placeholder="eg. *some?movie*,*some?show*s01*" tooltip={<div><p>This field has full regex support (Golang flavour).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a><br /><br /><p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p></div>} />
|
||||
<RegexTextAreaField name="except_description" label="Except description" useRegex={values.use_regex_description} columns={6} placeholder="eg. *bad?movie*,*bad?show*s03*" tooltip={<div><p>This field has full regex support (Golang flavour).</p><a href='https://autobrr.com/filters#advanced' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters#advanced</a><br /><br /><p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p></div>} />
|
||||
<RegexTextAreaField
|
||||
name="match_description"
|
||||
label="Match description"
|
||||
useRegex={values.use_regex_description}
|
||||
columns={6}
|
||||
placeholder="eg. *some?movie*,*some?show*s01*"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field has full regex support (Golang flavour).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
<br />
|
||||
<br />
|
||||
<p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
<RegexTextAreaField
|
||||
name="except_description"
|
||||
label="Except description"
|
||||
useRegex={values.use_regex_description}
|
||||
columns={6}
|
||||
placeholder="eg. *bad?movie*,*bad?show*s03*"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>This field has full regex support (Golang flavour).</p>
|
||||
<DocsLink href="https://autobrr.com/filters#advanced" />
|
||||
<br />
|
||||
<br />
|
||||
<p>Remember to tick <b>Use Regex</b> below if using more than <code>*</code> and <code>?</code>.</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
{/*</div>*/}
|
||||
|
||||
<div className="col-span-6">
|
||||
|
@ -665,12 +1225,53 @@ export function Advanced({ values }: AdvancedProps) {
|
|||
</div>
|
||||
</CollapsableSection>
|
||||
|
||||
<CollapsableSection defaultOpen={true} title="Freeleech" subtitle="Match only freeleech and freeleech percent.">
|
||||
<CollapsableSection
|
||||
defaultOpen={true}
|
||||
title="Freeleech"
|
||||
subtitle="Match only freeleech and freeleech percent."
|
||||
>
|
||||
<div className="col-span-6">
|
||||
<SwitchGroup name="freeleech" label="Freeleech" tooltip={<div><p>Freeleech may be announced as a binary true/false value or as a percentage, depending on the indexer. Use either or both, depending on the indexers you use.</p><br /><p>See who uses what in the documentation: <a href='https://autobrr.com/filters/freeleech' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/freeleech</a></p></div>} />
|
||||
<SwitchGroup
|
||||
name="freeleech"
|
||||
label="Freeleech"
|
||||
tooltip={
|
||||
<div>
|
||||
<p>
|
||||
Freeleech may be announced as a binary true/false value or as
|
||||
a percentage, depending on the indexer. Use either or both,
|
||||
depending on the indexers you use.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
See who uses what in the documentation:{" "}
|
||||
<DocsLink href="https://autobrr.com/filters/freeleech" />
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<TextField name="freeleech_percent" label="Freeleech percent" disabled={values.freeleech} tooltip={<div><p>Freeleech may be announced as a binary true/false value or as a percentage, depending on the indexer. Use either or both, depending on the indexers you use.</p><br /><p>See who uses what in the documentation: <a href='https://autobrr.com/filters/freeleech' className='text-blue-400 visited:text-blue-400' target='_blank'>https://autobrr.com/filters/freeleech</a></p></div>} columns={6} placeholder="eg. 50,75-100" />
|
||||
<TextField
|
||||
name="freeleech_percent"
|
||||
label="Freeleech percent"
|
||||
disabled={values.freeleech}
|
||||
tooltip={
|
||||
<div>
|
||||
<p>
|
||||
Freeleech may be announced as a binary true/false value or as a
|
||||
percentage, depending on the indexer. Use either or both,
|
||||
depending on the indexers you use.
|
||||
</p>
|
||||
<br />
|
||||
<p>
|
||||
See who uses what in the documentation:{" "}
|
||||
<DocsLink href="https://autobrr.com/filters/freeleech" />
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
columns={6}
|
||||
placeholder="eg. 50,75-100"
|
||||
/>
|
||||
</CollapsableSection>
|
||||
</div>
|
||||
);
|
||||
|
|
|
@ -19,6 +19,7 @@ import {
|
|||
import { ChevronRightIcon } from "@heroicons/react/24/solid";
|
||||
import { DeleteModal } from "@components/modals";
|
||||
import { ArrowDownIcon, ArrowUpIcon } from "@heroicons/react/24/outline";
|
||||
import { DocsLink } from "@components/ExternalLink";
|
||||
|
||||
export function External() {
|
||||
const { values } = useFormikContext<Filter>();
|
||||
|
@ -261,11 +262,7 @@ const TypeForm = ({ external, idx }: TypeFormProps) => {
|
|||
For custom commands you should specify the full path to the binary/program
|
||||
you want to run. And you can include your own static variables:
|
||||
</p>
|
||||
<a
|
||||
href="https://autobrr.com/filters/actions#custom-commands--exec"
|
||||
className="text-blue-400 visited:text-blue-400"
|
||||
target="_blank">https://autobrr.com/filters/actions#custom-commands--exec
|
||||
</a>
|
||||
<DocsLink href="https://autobrr.com/filters/actions#custom-commands--exec" />
|
||||
</div>
|
||||
}
|
||||
/>
|
||||
|
|
|
@ -10,7 +10,6 @@ import { Listbox, Menu, Switch, Transition } from "@headlessui/react";
|
|||
import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query";
|
||||
import { FormikValues } from "formik";
|
||||
import { useCallback } from "react";
|
||||
import { Tooltip } from "react-tooltip";
|
||||
import {
|
||||
ArrowsRightLeftIcon,
|
||||
CheckIcon,
|
||||
|
@ -35,6 +34,7 @@ import { EmptyListState } from "@components/emptystates";
|
|||
import { DeleteModal } from "@components/modals";
|
||||
|
||||
import { Importer } from "./Importer";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
|
||||
export const filterKeys = {
|
||||
all: ["filters"] as const,
|
||||
|
@ -96,7 +96,7 @@ export function Filters() {
|
|||
setIsOpen={setShowImportModal}
|
||||
/>
|
||||
|
||||
<div className="flex justify-between items-center flex-col sm:flex-row my-6 max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<div className="flex justify-between items-center flex-row flex-wrap my-6 max-w-screen-xl mx-auto px-4 sm:px-6 lg:px-8">
|
||||
<h1 className="text-3xl font-bold text-black dark:text-white">Filters</h1>
|
||||
<Menu as="div" className="relative">
|
||||
{({ open }) => (
|
||||
|
@ -635,49 +635,30 @@ function FilterListItem({ filter, values, idx }: FilterListItemProps) {
|
|||
Priority: {filter.priority}
|
||||
</span>
|
||||
<span className="whitespace-nowrap text-xs font-medium text-gray-600 dark:text-gray-400">
|
||||
<Link
|
||||
to={`${filter.id.toString()}/actions`}
|
||||
className="hover:text-black dark:hover:text-gray-300"
|
||||
>
|
||||
<span
|
||||
id={`tooltip-actions-${filter.id}`}
|
||||
className="flex items-center hover:cursor-pointer"
|
||||
>
|
||||
<span className={classNames(filter.actions_count == 0 ? "text-red-500" : "")}>
|
||||
<span
|
||||
className={
|
||||
classNames(
|
||||
filter.actions_count == 0 ? "hover:text-red-400 dark:hover:text-red-400" : ""
|
||||
)
|
||||
}
|
||||
>
|
||||
<Tooltip
|
||||
label={
|
||||
<Link
|
||||
to={`${filter.id.toString()}/actions`}
|
||||
className="flex items-center cursor-pointer hover:text-black dark:hover:text-gray-300"
|
||||
>
|
||||
<span className={classNames(!filter.actions_count ? "text-red-500 hover:text-red-400 dark:hover:text-red-400" : "")}>
|
||||
Actions: {filter.actions_count}
|
||||
</span>
|
||||
</span>
|
||||
{filter.actions_count === 0 && (
|
||||
<>
|
||||
{!filter.actions_count && (
|
||||
<span className="mr-2 ml-2 flex h-3 w-3 relative">
|
||||
<span className="animate-ping inline-flex h-full w-full rounded-full dark:bg-red-500 bg-red-400 opacity-75" />
|
||||
<span
|
||||
className="inline-flex absolute rounded-full h-3 w-3 dark:bg-red-500 bg-red-400"
|
||||
/>
|
||||
</span>
|
||||
<span className="text-sm text-gray-800 dark:text-gray-500">
|
||||
<Tooltip
|
||||
style={{ width: "350px", fontSize: "12px", textTransform: "none", fontWeight: "normal", borderRadius: "0.375rem", backgroundColor: "#34343A", color: "#fff", whiteSpace: "pre-wrap", overflow: "hidden", textOverflow: "ellipsis" }}
|
||||
delayShow={100}
|
||||
delayHide={150}
|
||||
data-html={true}
|
||||
place="right"
|
||||
data-tooltip-id={`tooltip-actions-${filter.id}`}
|
||||
>
|
||||
<p>You need to setup an action in the filter otherwise you will not get any snatches.</p>
|
||||
</Tooltip>
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</Link>
|
||||
)}
|
||||
</Link>
|
||||
}
|
||||
>
|
||||
{!filter.actions_count ? (
|
||||
<>{"You need to setup an action in the filter otherwise you will not get any snatches."}</>
|
||||
) : null}
|
||||
</Tooltip>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -140,7 +140,8 @@ export const PushStatusSelectColumnFilter = ({
|
|||
))}
|
||||
</ListboxFilter>
|
||||
</div>
|
||||
);};
|
||||
);
|
||||
}
|
||||
|
||||
export const SearchColumnFilter = ({
|
||||
column: { filterValue, setFilter, id }
|
||||
|
@ -161,4 +162,5 @@ export const SearchColumnFilter = ({
|
|||
placeholder="Search releases..."
|
||||
/>
|
||||
</div>
|
||||
);};
|
||||
);
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import { IndexerSelectColumnFilter, PushStatusSelectColumnFilter, SearchColumnFi
|
|||
import { classNames } from "@utils";
|
||||
import { ArrowTopRightOnSquareIcon, ArrowDownTrayIcon } from "@heroicons/react/24/outline";
|
||||
import { Tooltip } from "@components/tooltips/Tooltip";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const releaseKeys = {
|
||||
all: ["releases"] as const,
|
||||
|
@ -103,24 +104,17 @@ export const ReleaseTable = () => {
|
|||
</Tooltip>
|
||||
<div className="flex mr-0">
|
||||
{props.row.original.download_url && (
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
<ExternalLink
|
||||
href={props.row.original.download_url}
|
||||
className="max-w-[90vw] px-2"
|
||||
className="px-2"
|
||||
>
|
||||
<ArrowDownTrayIcon className="h-5 w-5 text-blue-400 hover:text-blue-500 dark:text-blue-500 dark:hover:text-blue-600" aria-hidden="true" />
|
||||
</a>
|
||||
</ExternalLink>
|
||||
)}
|
||||
{props.row.original.info_url && (
|
||||
<a
|
||||
rel="noopener noreferrer"
|
||||
target="_blank"
|
||||
href={props.row.original.info_url}
|
||||
className="max-w-[90vw]"
|
||||
>
|
||||
<ExternalLink href={props.row.original.info_url}>
|
||||
<ArrowTopRightOnSquareIcon className="h-5 w-5 text-blue-400 hover:text-blue-500 dark:text-blue-500 dark:hover:text-blue-600" aria-hidden="true" />
|
||||
</a>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -11,6 +11,7 @@ import { Checkbox } from "@components/Checkbox";
|
|||
import { SettingsContext } from "@utils/Context";
|
||||
import { GithubRelease } from "@app/types/Update";
|
||||
import Toast from "@components/notifications/Toast";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
interface RowItemProps {
|
||||
label: string;
|
||||
|
@ -63,9 +64,12 @@ const RowItemVersion = ({ label, value, title, newUpdate }: RowItemProps) => {
|
|||
<dd className="mt-1 text-gray-900 dark:text-gray-300 text-sm sm:mt-0 sm:col-span-2 break-all truncate">
|
||||
<span className="px-1.5 py-1 bg-gray-200 dark:bg-gray-700 rounded shadow">{value}</span>
|
||||
{newUpdate && newUpdate.html_url && (
|
||||
<span>
|
||||
<a href={newUpdate.html_url} target="_blank" rel="noopener noreferrer"><span className="ml-2 inline-flex items-center rounded-md bg-green-100 px-2.5 py-0.5 text-sm font-medium text-green-800">{newUpdate.name} available!</span></a>
|
||||
</span>
|
||||
<ExternalLink
|
||||
href={newUpdate.html_url}
|
||||
className="ml-2 inline-flex items-center rounded-md bg-green-100 px-2.5 py-0.5 text-sm font-medium text-green-800"
|
||||
>
|
||||
{newUpdate.name} available!
|
||||
</ExternalLink>
|
||||
)}
|
||||
</dd>
|
||||
</div>
|
||||
|
@ -184,10 +188,12 @@ function ApplicationSettings() {
|
|||
<Checkbox
|
||||
label="WebUI Debug mode"
|
||||
value={settings.debug}
|
||||
setValue={(newValue: boolean) => setSettings({
|
||||
...settings,
|
||||
debug: newValue
|
||||
})}
|
||||
setValue={
|
||||
(newValue: boolean) => setSettings((prevState) => ({
|
||||
...prevState,
|
||||
debug: newValue
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div className="px-4 sm:px-6 py-1">
|
||||
|
@ -205,15 +211,16 @@ function ApplicationSettings() {
|
|||
label="Dark theme"
|
||||
description="Switch between dark and light theme."
|
||||
value={settings.darkTheme}
|
||||
setValue={(newValue: boolean) => setSettings({
|
||||
...settings,
|
||||
darkTheme: newValue
|
||||
})}
|
||||
setValue={
|
||||
(newValue: boolean) => setSettings((prevState) => ({
|
||||
...prevState,
|
||||
darkTheme: newValue
|
||||
}))
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
|
|
@ -24,6 +24,7 @@ import { FeedUpdateForm } from "@forms/settings/FeedForms";
|
|||
import { EmptySimple } from "@components/emptystates";
|
||||
import { ImplementationBadges } from "./Indexer";
|
||||
import { ArrowPathIcon } from "@heroicons/react/24/solid";
|
||||
import { ExternalLink } from "@components/ExternalLink";
|
||||
|
||||
export const feedKeys = {
|
||||
all: ["feeds"] as const,
|
||||
|
@ -354,10 +355,8 @@ const FeedItemDropdown = ({
|
|||
<div>
|
||||
<Menu.Item>
|
||||
{({ active }) => (
|
||||
<a
|
||||
<ExternalLink
|
||||
href={`${baseUrl()}api/feeds/${feed.id}/latest`}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className={classNames(
|
||||
active ? "bg-blue-600 text-white" : "text-gray-900 dark:text-gray-300",
|
||||
"font-medium group flex rounded-md items-center w-full px-2 py-2 text-sm"
|
||||
|
@ -371,7 +370,7 @@ const FeedItemDropdown = ({
|
|||
aria-hidden="true"
|
||||
/>
|
||||
View latest run
|
||||
</a>
|
||||
</ExternalLink>
|
||||
)}
|
||||
</Menu.Item>
|
||||
<Menu.Item>
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue