diff --git a/web/src/screens/filters/details.tsx b/web/src/screens/filters/details.tsx index be484b9..d325de7 100644 --- a/web/src/screens/filters/details.tsx +++ b/web/src/screens/filters/details.tsx @@ -25,8 +25,6 @@ import { APIClient } from "../../api/APIClient"; import { useToggle } from "../../hooks/hooks"; import { classNames } from "../../utils"; -import { CustomTooltip } from "../../components/tooltips/CustomTooltip"; - import { CheckboxField, IndexerMultiSelect, @@ -319,7 +317,7 @@ export default function FilterDetails() { ); } -export function General() { +export function General(){ const { isLoading, data: indexers } = useQuery( ["filters", "indexer_list"], () => APIClient.indexers.getOptions(), @@ -334,7 +332,6 @@ export function General() { return (
-
@@ -360,7 +357,6 @@ export function General() {
-
); } diff --git a/web/src/screens/filters/list.tsx b/web/src/screens/filters/list.tsx index 1856968..f679cc4 100644 --- a/web/src/screens/filters/list.tsx +++ b/web/src/screens/filters/list.tsx @@ -3,15 +3,22 @@ import { Link } from "react-router-dom"; import { toast } from "react-hot-toast"; import { Listbox, Menu, Switch, Transition } from "@headlessui/react"; import { useMutation, useQuery, useQueryClient } from "react-query"; +import { FormikValues } from "formik"; +import { useCallback } from "react"; + +import { Tooltip } from "react-tooltip"; + import { ArrowsRightLeftIcon, CheckIcon, ChevronDownIcon, + PlusIcon, DocumentDuplicateIcon, EllipsisHorizontalIcon, PencilSquareIcon, - TrashIcon + TrashIcon, + ExclamationTriangleIcon } from "@heroicons/react/24/outline"; import { queryClient } from "../../App"; @@ -22,6 +29,7 @@ import { APIClient } from "../../api/APIClient"; import Toast from "../../components/notifications/Toast"; import { EmptyListState } from "../../components/emptystates"; import { DeleteModal } from "../../components/modals"; +import { ArrowDownTrayIcon } from "@heroicons/react/24/solid"; type FilterListState = { indexerFilter: string[], @@ -71,9 +79,69 @@ const FilterListReducer = (state: FilterListState, action: Actions): FilterListS } }; -export default function Filters() { +interface FilterProps { + values?: FormikValues; +} + +export default function Filters({}: FilterProps){ + + const queryClient = useQueryClient(); + const [createFilterIsOpen, toggleCreateFilter] = useToggle(false); + const [showImportModal, setShowImportModal] = useState(false); + const [importJson, setImportJson] = useState(""); + + // This function handles the import of a filter from a JSON string + const handleImportJson = async () => { + try { + const importedData = JSON.parse(importJson); + + // Extract the filter data and name from the imported object + const importedFilter = importedData.data; + const filterName = importedData.name; + + // Check if the required properties are present and add them with default values if they are missing + const requiredProperties = ["resolutions", "sources", "codecs", "containers"]; + requiredProperties.forEach((property) => { + if (!importedFilter.hasOwnProperty(property)) { + importedFilter[property] = []; + } + }); + + // Fetch existing filters from the API + const existingFilters = await APIClient.filters.getAll(); + + // Create a unique filter title by appending an incremental number if title is taken by another filter + let nameCounter = 0; + let uniqueFilterName = filterName; + while (existingFilters.some((filter) => filter.name === uniqueFilterName)) { + nameCounter++; + uniqueFilterName = `${filterName}-${nameCounter}`; + } + + // Create a new filter using the API + const newFilter: Filter = { + ...importedFilter, + name: uniqueFilterName + }; + + await APIClient.filters.create(newFilter); + + // Update the filter list + queryClient.invalidateQueries("filters"); + + toast.custom((t) => ); + setShowImportModal(false); + } catch (error) { + // Log the error and show an error toast message + console.error("Error:", error); + toast.custom((t) => ); + } + }; + + const [showDropdown, setShowDropdown] = useState(false); + return (
@@ -81,19 +149,68 @@ export default function Filters() {

- Filters + Filters

-
+
+ + {showDropdown && ( +
+ +
+ )}
+ {showImportModal && ( +
+
+

Import Filter JSON

+