diff --git a/web/package.json b/web/package.json index 6f4a24b..1f2b6e3 100644 --- a/web/package.json +++ b/web/package.json @@ -31,7 +31,9 @@ "react-tooltip": "^5.5.2", "stacktracey": "^2.1.8", "vite-plugin-pwa": "^0.14.6", - "workbox-window": "^6.5.4" + "workbox-window": "^6.5.4", + "zod": "^3.21.4", + "zod-formik-adapter": "^1.2.0" }, "scripts": { "start": "vite", diff --git a/web/src/components/inputs/select.tsx b/web/src/components/inputs/select.tsx index c571ef0..abe5ad6 100644 --- a/web/src/components/inputs/select.tsx +++ b/web/src/components/inputs/select.tsx @@ -116,21 +116,27 @@ export const IndexerMultiSelect = ({ {({ field, + meta, form: { setFieldValue } }: FieldProps) => ( - ({ - value: item.id, label: item.name - }))} - onChange={(values: MultiSelectOption[]) => { - const item = values && values.map((i) => ({ id: i.value, name: i.label })); - setFieldValue(field.name, item); - }} - className={settingsContext.darkTheme ? "dark" : ""} - /> + <> + ({ + value: item.id, label: item.name + }))} + onChange={(values: MultiSelectOption[]) => { + const item = values && values.map((i) => ({ id: i.value, name: i.label })); + setFieldValue(field.name, item); + }} + className={settingsContext.darkTheme ? "dark" : ""} + /> + {meta.touched && meta.error && ( +

* {meta.error}

+ )} + )}
@@ -153,6 +159,7 @@ export function DownloadClientSelect({ {({ field, + meta, form: { setFieldValue } }: FieldProps) => ( + {meta.touched && meta.error && ( +

* {meta.error}

+ )} )} diff --git a/web/src/screens/filters/action.tsx b/web/src/screens/filters/action.tsx index 22d5edf..d35f61b 100644 --- a/web/src/screens/filters/action.tsx +++ b/web/src/screens/filters/action.tsx @@ -1,20 +1,24 @@ +import React, { Fragment, useEffect, useRef, useState } from "react"; +import { useQuery } from "@tanstack/react-query"; +import { Field, FieldArray, FieldProps, FormikValues, useFormikContext } from "formik"; +import { Dialog, Switch as SwitchBasic, Transition } from "@headlessui/react"; +import { ChevronRightIcon } from "@heroicons/react/24/solid"; +import { Link } from "react-router-dom"; + +import { + ActionContentLayoutOptions, + ActionRtorrentRenameOptions, + ActionTypeNameMap, + ActionTypeOptions +} from "@domain/constants"; import { AlertWarning } from "@components/alerts"; import { DownloadClientSelect, NumberField, Select, SwitchGroup, TextField } from "@components/inputs"; -import { ActionContentLayoutOptions, ActionRtorrentRenameOptions, ActionTypeNameMap, ActionTypeOptions } from "@domain/constants"; -import React, { Fragment, useRef, useEffect, useState } from "react"; -import { useQuery } from "@tanstack/react-query"; import { APIClient } from "@api/APIClient"; -import { Field, FieldArray, FieldProps, FormikValues } from "formik"; import { EmptyListState } from "@components/emptystates"; import { useToggle } from "@hooks/hooks"; import { classNames } from "@utils"; -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"; -import { Link } from "react-router-dom"; -import { useFormikContext } from "formik"; import { TextArea } from "@components/inputs/input"; interface FilterActionsProps { @@ -29,7 +33,8 @@ export function FilterActions({ filter, values }: FilterActionsProps) { { refetchOnWindowFocus: false } ); - const newAction = { + const newAction: Action = { + id: 0, name: "new action", enabled: true, type: "TEST", @@ -43,7 +48,7 @@ export function FilterActions({ filter, values }: FilterActionsProps) { paused: false, ignore_rules: false, skip_hash_check: false, - content_layout: "", + content_layout: "" || undefined, limit_upload_speed: 0, limit_download_speed: 0, limit_ratio: 0, @@ -57,8 +62,8 @@ export function FilterActions({ filter, values }: FilterActionsProps) { webhook_type: "", webhook_method: "", webhook_data: "", - webhook_headers: [] - // client_id: 0, + webhook_headers: [], + client_id: 0 }; return ( @@ -108,7 +113,7 @@ interface TypeFormProps { } const TypeForm = ({ action, idx, clients }: TypeFormProps) => { - const { setFieldValue } = useFormikContext(); + const { setFieldValue } = useFormikContext(); const resetClientField = (action: Action, idx: number, prevActionType: string): void => { const fieldName = `actions.${idx}.client_id`; @@ -127,7 +132,7 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => { action.type === "READARR" || action.type === "SABNZBD" )) { - setFieldValue(fieldName, ""); // Reset the client_id field value + setFieldValue(fieldName, 0); // Reset the client_id field value } }; @@ -137,7 +142,8 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => { resetClientField(action, idx, prevActionType); } setPrevActionType(action.type); - }, [action.type, idx, setFieldValue]); + }, [action.type, idx, setFieldValue]); + switch (action.type) { case "TEST": return ( @@ -209,7 +215,7 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => { label="Save path" columns={6} 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
} /> + 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
} /> @@ -219,13 +225,13 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => { label="Category" columns={6} placeholder="eg. category" - tooltip={

The field can use macros to transform/add values from metadata:

https://autobrr.com/filters/actions#macros
} /> + tooltip={

The field can use macros to transform/add values from metadata:

https://autobrr.com/filters/actions#macros
} />

The field can use macros to transform/add values from metadata:

https://autobrr.com/filters/actions#macros
} /> + tooltip={

The field can use macros to transform/add values from metadata:

https://autobrr.com/filters/actions#macros
} /> @@ -266,7 +272,7 @@ const TypeForm = ({ action, idx, clients }: TypeFormProps) => {

Choose to ignore rules set in Client Settings.

} /> + tooltip={

Choose to ignore rules set in Client Settings.

} />