@@ -132,6 +143,7 @@ interface NumberFieldWideProps {
placeholder?: string;
defaultValue?: number;
required?: boolean;
+ tooltip?: JSX.Element;
}
export const NumberFieldWide = ({
@@ -140,6 +152,7 @@ export const NumberFieldWide = ({
placeholder,
help,
defaultValue,
+ tooltip,
required
}: NumberFieldWideProps) => (
@@ -148,7 +161,10 @@ export const NumberFieldWide = ({
htmlFor={name}
className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2"
>
- {label} {required &&
*}
+
+ {label} {tooltip && ({tooltip})}
+
+
@@ -187,12 +203,14 @@ interface SwitchGroupWideProps {
description?: string;
defaultValue?: boolean;
className?: string;
+ tooltip?: JSX.Element;
}
export const SwitchGroupWide = ({
name,
label,
description,
+ tooltip,
defaultValue
}: SwitchGroupWideProps) => (
@@ -200,7 +218,9 @@ export const SwitchGroupWide = ({
- {label}
+
+ {label} {tooltip && ({tooltip})}
+
{description && (
@@ -350,15 +370,19 @@ export const SelectFieldWide = ({
name,
label,
optionDefaultText,
+ tooltip,
options
}: SelectFieldProps) => (
diff --git a/web/src/components/inputs/select.tsx b/web/src/components/inputs/select.tsx
index 45ddfd2..f522458 100644
--- a/web/src/components/inputs/select.tsx
+++ b/web/src/components/inputs/select.tsx
@@ -1,4 +1,4 @@
-import { Fragment } from "react";
+import React, { Fragment } from "react";
import { Field, FieldProps } from "formik";
import { Listbox, Transition } from "@headlessui/react";
import { CheckIcon, ChevronUpDownIcon } from "@heroicons/react/24/solid";
@@ -6,6 +6,7 @@ import { MultiSelect as RMSC } from "react-multi-select-component";
import { classNames, COL_WIDTHS } from "../../utils";
import { SettingsContext } from "../../utils/Context";
+import { CustomTooltip } from "../tooltips/CustomTooltip";
export interface MultiSelectOption {
value: string | number;
@@ -21,6 +22,7 @@ interface MultiSelectProps {
columns?: COL_WIDTHS;
creatable?: boolean;
disabled?: boolean;
+ tooltip?: JSX.Element;
}
export const MultiSelect = ({
@@ -29,6 +31,7 @@ export const MultiSelect = ({
options,
columns,
creatable,
+ tooltip,
disabled
}: MultiSelectProps) => {
const settingsContext = SettingsContext.useValue();
@@ -46,10 +49,13 @@ export const MultiSelect = ({
)}
>
@@ -155,7 +161,7 @@ export function DownloadClientSelect({
{({ open }) => (
<>
- Client
+ Client
@@ -244,11 +250,13 @@ export interface SelectFieldProps {
label: string;
optionDefaultText: string;
options: SelectFieldOption[];
+ tooltip?: JSX.Element;
}
export const Select = ({
name,
label,
+ tooltip,
optionDefaultText,
options
}: SelectFieldProps) => {
@@ -265,8 +273,13 @@ export const Select = ({
>
{({ open }) => (
<>
-
- {label}
+
+
+ {label}
+ {tooltip && (
+ {tooltip}
+ )}
+
diff --git a/web/src/components/inputs/switch.tsx b/web/src/components/inputs/switch.tsx
index 8d38be2..b0e6690 100644
--- a/web/src/components/inputs/switch.tsx
+++ b/web/src/components/inputs/switch.tsx
@@ -3,6 +3,7 @@ import type { FieldInputProps, FieldMetaProps, FieldProps, FormikProps, FormikVa
import { Field } from "formik";
import { Switch as HeadlessSwitch } from "@headlessui/react";
import { classNames } from "../../utils";
+import { CustomTooltip } from "../tooltips/CustomTooltip";
type SwitchProps = {
label?: string
@@ -69,19 +70,26 @@ interface SwitchGroupProps {
description?: string;
className?: string;
heading?: boolean;
+ tooltip?: JSX.Element;
}
const SwitchGroup = ({
name,
label,
description,
+ tooltip,
heading
}: SwitchGroupProps) => (
{label &&
-
- {label}
+
+ {label}
+ {tooltip && (
+ {tooltip}
+ )}
+
{description && (
diff --git a/web/src/components/tooltips/CustomTooltip.css b/web/src/components/tooltips/CustomTooltip.css
new file mode 100644
index 0000000..aefb64b
--- /dev/null
+++ b/web/src/components/tooltips/CustomTooltip.css
@@ -0,0 +1,11 @@
+.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;
+}
diff --git a/web/src/components/tooltips/CustomTooltip.tsx b/web/src/components/tooltips/CustomTooltip.tsx
new file mode 100644
index 0000000..34dd3e4
--- /dev/null
+++ b/web/src/components/tooltips/CustomTooltip.tsx
@@ -0,0 +1,27 @@
+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 (
+
+ );
+};
\ No newline at end of file
diff --git a/web/src/forms/settings/DownloadClientForms.tsx b/web/src/forms/settings/DownloadClientForms.tsx
index f3a090a..b1e042e 100644
--- a/web/src/forms/settings/DownloadClientForms.tsx
+++ b/web/src/forms/settings/DownloadClientForms.tsx
@@ -62,6 +62,7 @@ function FormFieldsDeluge() {
name="host"
label="Host"
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port"
+ tooltip={}
/>
See guides for how to connect to the *arr suite for various server types in our docs.
Dedicated servers:
https://autobrr.com/configuration/download-clients/dedicated/Shared seedbox providers:
https://autobrr.com/configuration/download-clients/shared-seedboxes }
/>
@@ -123,6 +125,7 @@ function FormFieldsQbit() {
name="host"
label="Host"
help="Eg. http(s)://client.domain.ltd, http(s)://domain.ltd/qbittorrent, http://domain.ltd:port"
+ tooltip={}
/>
{port > 0 && (
@@ -172,7 +175,7 @@ function FormFieldsPorla() {
- )
+ );
}
function FormFieldsRTorrent() {
@@ -182,6 +185,7 @@ function FormFieldsRTorrent() {
name="host"
label="Host"
help="Eg. http(s)://client.domain.ltd/RPC2, http(s)://domain.ltd/client, http(s)://domain.ltd/RPC2"
+ tooltip={}
/>
);
@@ -198,6 +202,7 @@ function FormFieldsTransmission() {
name="host"
label="Host"
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd"
+ tooltip={}
/>
@@ -253,7 +258,7 @@ function FormFieldsRulesBasic() {
{settings && settings.rules?.enabled === true && (
-
+ Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.
https://autobrr.com/configuration/download-clients/dedicated#deluge-rules
See recommendations for various server types here:
https://autobrr.com/filters/examples#build-buffer} />
)}
);
@@ -282,7 +287,7 @@ function FormFieldsRules() {
+ tooltip={<>
Limit the amount of active downloads (0 is unlimited), to give the maximum amount of bandwidth and disk for the downloads.
https://autobrr.com/configuration/download-clients/dedicated#qbittorrent-rulesSee recommendations for various server types here:
https://autobrr.com/filters/examples#build-buffer>} />
Choose whether to respect or ignore the Max active downloads
setting before checking speed thresholds.}
/>
(
{
{ind.irc.settings.map((f: IndexerSetting, idx: number) => {
switch (f.type) {
case "text":
- return ;
+ return Please read our IRC guide if you are unfamiliar with IRC.
https://autobrr.com/configuration/irc } />;
case "secret":
if (f.name === "invite_command") {
return ;
@@ -171,7 +173,7 @@ const SettingFields = (ind: IndexerDefinition, indexer: string) => {
);
case "secret":
return (
-
+ } />
);
}
return null;
@@ -548,7 +550,7 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
);
case "secret":
return (
-
+ } />
);
}
return null;
diff --git a/web/src/index.tsx b/web/src/index.tsx
index 73b3342..4efab41 100644
--- a/web/src/index.tsx
+++ b/web/src/index.tsx
@@ -3,6 +3,7 @@ import { createRoot } from "react-dom/client";
import "@fontsource/inter/variable.css";
import "./index.css";
+import "react-tooltip/dist/react-tooltip.css";
import { App } from "./App";
import { InitializeGlobalContext } from "./utils/Context";
diff --git a/web/src/screens/filters/action.tsx b/web/src/screens/filters/action.tsx
index 52705c5..0dfee04 100644
--- a/web/src/screens/filters/action.tsx
+++ b/web/src/screens/filters/action.tsx
@@ -12,6 +12,7 @@ import { Dialog, Switch as SwitchBasic, Transition } from "@headlessui/react";
import { ChevronRightIcon } from "@heroicons/react/24/solid";
import { DeleteModal } from "../../components/modals";
import { CollapsableSection } from "./details";
+import { CustomTooltip } from "../../components/tooltips/CustomTooltip";
interface FilterActionsProps {
filter: Filter;
@@ -173,8 +174,8 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
name={`actions.${idx}.save_path`}
label="Save path"
columns={6}
- placeholder="eg. /full/path/to/watch_folder"
- />
+ placeholder="eg. /full/path/to/download_folder"
+ tooltip={Set a custom save path for this action. Automatic Torrent Management will take care of this if using qBittorrent with categories.
The field can use macros to transform/add values from metadata:
https://autobrr.com/filters/actions#macros } />
@@ -184,13 +185,13 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
label="Category"
columns={6}
placeholder="eg. category"
- />
+ tooltip={
} />
+ tooltip={
} />