@@ -361,45 +362,38 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
initialValues={initialValues}
>
{({ values }: any) => (
- <>
-
-
-
-
-
-
- {({ input, meta }) => (
-
-
- {meta.touched && meta.error &&
- {meta.error}}
-
- )}
-
+
+
+
+
-
-
-
-
-
- {renderSettingFields(indexer.settings)}
-
+
+ {({ field, meta }: FieldProps) => (
+
+
+ {meta.touched && meta.error &&
+ {meta.error}}
+
+ )}
+
- >
- )}
+
+
+
+ {renderSettingFields(indexer.settings)}
+
+ )}
)
}
\ No newline at end of file
diff --git a/web/src/forms/settings/IrcForms.tsx b/web/src/forms/settings/IrcForms.tsx
index 4958fe3..22badd0 100644
--- a/web/src/forms/settings/IrcForms.tsx
+++ b/web/src/forms/settings/IrcForms.tsx
@@ -1,19 +1,83 @@
import { useMutation } from "react-query";
-import { Network } from "../../domain/interfaces";
+import { Channel, Network } from "../../domain/interfaces";
import { XIcon } from "@heroicons/react/solid";
-import { Field } from "react-final-form";
-import { SwitchGroup, TextFieldWide } from "../../components/inputs";
import { queryClient } from "../../App";
-import arrayMutators from "final-form-arrays";
-import { FieldArray } from "react-final-form-arrays";
+import { Field, FieldArray, FieldProps } from "formik";
import APIClient from "../../api/APIClient";
-import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
+
+import { TextFieldWide, PasswordFieldWide, SwitchGroupWide, NumberFieldWide } from "../../components/inputs/input_wide";
import { toast } from 'react-hot-toast';
import Toast from '../../components/notifications/Toast';
import { SlideOver } from "../../components/panels";
+function ChannelsFieldArray({ values }: any) {
+ return (
+
+
+ {({ remove, push }) => (
+
+ {values && values.channels.length > 0 ? (
+ values.channels.map((_channel: Channel, index: number) => (
+
+ ))
+ ) : (
+
+ No channels!
+
+ )}
+
+
+ )}
+
+
+ )
+}
+
export function IrcNetworkAddForm({ isOpen, toggle }: any) {
const mutation = useMutation((network: Network) => APIClient.irc.createNetwork(network), {
onSuccess: (data) => {
@@ -66,15 +130,13 @@ export function IrcNetworkAddForm({ isOpen, toggle }: any) {
name: "",
enabled: true,
server: "",
+ port: 6667,
tls: false,
pass: "",
nickserv: {
account: ""
- }
- }
-
- const mutators = {
- ...arrayMutators
+ },
+ channels: [],
}
return (
@@ -85,19 +147,16 @@ export function IrcNetworkAddForm({ isOpen, toggle }: any) {
toggle={toggle}
onSubmit={onSubmit}
initialValues={initialValues}
- mutators={mutators}
validate={validate}
>
- {() => (
+ {(values) => (
<>
-
-
-
+
@@ -105,7 +164,7 @@ export function IrcNetworkAddForm({ isOpen, toggle }: any) {
-
+
@@ -117,57 +176,7 @@ export function IrcNetworkAddForm({ isOpen, toggle }: any) {
-
-
-
- {({ fields }) => (
-
- {fields && (fields.length as any) > 0 ? (
- fields.map((name, index) => (
-
-
-
-
-
-
-
-
- ))
- ) : (
-
- No channels!
-
- )}
-
-
- )}
-
-
+
>
)}
@@ -193,8 +202,6 @@ export function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
})
const onSubmit = (data: any) => {
- console.log(data)
-
// easy way to split textarea lines into array of strings for each newline.
// parse on the field didn't really work.
// TODO fix connect_commands on network update
@@ -241,14 +248,9 @@ export function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
nickserv: network.nickserv,
pass: network.pass,
invite_command: network.invite_command,
- // connect_commands: network.connect_commands,
channels: network.channels
}
- const mutators = {
- ...arrayMutators
- }
-
return (
- {() => (
+ {(values) => (
<>
-
-
+
@@ -277,7 +277,7 @@ export function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
-
+
@@ -289,57 +289,7 @@ export function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
-
-
-
- {({ fields }) => (
-
- {fields && (fields.length as any) > 0 ? (
- fields.map((name, index) => (
-
-
-
-
-
-
-
-
- ))
- ) : (
-
- No channels!
-
- )}
-
-
- )}
-
-
+
>
)}
diff --git a/web/src/screens/Dashboard.tsx b/web/src/screens/Dashboard.tsx
index 4807c3b..d6bb5f2 100644
--- a/web/src/screens/Dashboard.tsx
+++ b/web/src/screens/Dashboard.tsx
@@ -5,7 +5,7 @@ import { useTable, useFilters, useGlobalFilter, useSortBy, usePagination } from
import APIClient from '../api/APIClient'
import { useQuery } from 'react-query'
import { ReleaseFindResponse, ReleaseStats } from '../domain/interfaces'
-import { EmptyListState } from '../components/EmptyListState'
+import { EmptyListState } from '../components/emptystates'
export function Dashboard() {
return (
diff --git a/web/src/screens/Settings.tsx b/web/src/screens/Settings.tsx
index 9d181f5..73cfcda 100644
--- a/web/src/screens/Settings.tsx
+++ b/web/src/screens/Settings.tsx
@@ -4,7 +4,7 @@ import IndexerSettings from "./settings/Indexer";
import IrcSettings from "./settings/Irc";
import ApplicationSettings from "./settings/Application";
import DownloadClientSettings from "./settings/DownloadClient";
-import {classNames} from "../styles/utils";
+import {classNames} from "../utils";
import ActionSettings from "./settings/Action";
const subNavigation = [
diff --git a/web/src/screens/auth/login.tsx b/web/src/screens/auth/login.tsx
index e25d965..69fc8cf 100644
--- a/web/src/screens/auth/login.tsx
+++ b/web/src/screens/auth/login.tsx
@@ -1,12 +1,12 @@
import { useMutation } from "react-query";
import APIClient from "../../api/APIClient";
-import { Form } from "react-final-form";
-import { PasswordField, TextField } from "../../components/inputs";
+import { Form, Formik } from "formik";
import { useRecoilState } from "recoil";
import { isLoggedIn } from "../../state/state";
import { useHistory } from "react-router-dom";
import { useEffect } from "react";
import logo from "../../logo.png"
+import { TextField, PasswordField } from "../../components/inputs";
interface loginData {
username: string;
@@ -32,9 +32,8 @@ function Login() {
},
})
- const onSubmit = (data: any, form: any) => {
+ const handleSubmit = (data: any) => {
mutation.mutate(data)
- form.reset()
}
return (
@@ -50,51 +49,34 @@ function Login() {
-
- )
- }}
-
+
+
+
+
+
+ )}
+
diff --git a/web/src/screens/filters/details.tsx b/web/src/screens/filters/details.tsx
index cb9d1c8..ffa4675 100644
--- a/web/src/screens/filters/details.tsx
+++ b/web/src/screens/filters/details.tsx
@@ -1,7 +1,7 @@
import { Fragment, useRef } from "react";
import { Dialog, Transition, Switch as SwitchBasic } from "@headlessui/react";
import { ChevronDownIcon, ChevronRightIcon, ExclamationIcon, } from '@heroicons/react/solid'
-import { EmptyListState } from "../../components/EmptyListState";
+import { EmptyListState } from "../../components/emptystates";
import {
NavLink,
@@ -17,14 +17,12 @@ import { useToggle } from "../../hooks/hooks";
import { useMutation, useQuery } from "react-query";
import { queryClient } from "../../App";
import { CONTAINER_OPTIONS, CODECS_OPTIONS, RESOLUTION_OPTIONS, SOURCES_OPTIONS, ActionTypeNameMap, ActionTypeOptions } from "../../domain/constants";
-import { TextField, SwitchGroup, Select, MultiSelect, NumberField, DownloadClientSelect } from "./inputs";
import DEBUG from "../../components/debug";
-import TitleSubtitle from "../../components/headings/TitleSubtitle";
-import { classNames } from "../../styles/utils";
+import { TitleSubtitle } from "../../components/headings";
+import { buildPath, classNames } from "../../utils";
import SelectM from "react-select";
import APIClient from "../../api/APIClient";
-import { buildPath } from "../../utils/utils"
import { toast } from 'react-hot-toast'
import Toast from '../../components/notifications/Toast';
@@ -32,6 +30,7 @@ import Toast from '../../components/notifications/Toast';
import { Field, FieldArray, Form, Formik } from "formik";
import { AlertWarning } from "../../components/alerts";
import { DeleteModal } from "../../components/modals";
+import { NumberField, TextField, SwitchGroup, Select, MultiSelect, DownloadClientSelect } from "../../components/inputs";
const tabs = [
{ name: 'General', href: '', current: true },
@@ -66,93 +65,21 @@ function TabNavLink({ item, url }: any) {
)
}
-const FormButtonsGroup = ({ deleteAction, reset, dirty }: any) => {
- const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false)
+const FormButtonsGroup = ({ values, deleteAction, reset, dirty }: any) => {
+ const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
- const cancelButtonRef = useRef(null)
+ const cancelModalButtonRef = useRef(null);
return (
-
-
-
-
+
@@ -665,8 +590,8 @@ function FilterActions({ filter, values }: FilterActionsProps) {
{values.actions.length > 0 ?
- {values.actions.map((action: any, index: any) => (
-
+ {values.actions.map((action: any, index: number) => (
+
))}
:
diff --git a/web/src/screens/filters/inputs/DownloadClientSelect.tsx b/web/src/screens/filters/inputs/DownloadClientSelect.tsx
deleted file mode 100644
index 4694c62..0000000
--- a/web/src/screens/filters/inputs/DownloadClientSelect.tsx
+++ /dev/null
@@ -1,109 +0,0 @@
-import { Fragment } from "react";
-import { Transition, Listbox } from "@headlessui/react";
-import { CheckIcon, SelectorIcon } from '@heroicons/react/solid';
-import { Action, DownloadClient } from "../../../domain/interfaces";
-import { classNames } from "../../../styles/utils";
-import { Field } from "formik";
-
-interface DownloadClientSelectProps {
- name: string;
- action: Action;
- clients: DownloadClient[];
-}
-
-export default function DownloadClientSelect({
- name, action, clients,
-}: DownloadClientSelectProps) {
- return (
-
-
- {({
- field,
- form: { setFieldValue },
- }: any) => (
- setFieldValue(field?.name, value)}
- >
- {({ open }) => (
- <>
-
- Client
-
-
-
-
- {field.value
- ? clients.find((c) => c.id === field.value)!.name
- : "Choose a client"}
-
- {/*Choose a client*/}
-
-
-
-
-
-
-
- {clients
- .filter((c) => c.type === action.type)
- .map((client: any) => (
- classNames(
- active
- ? "text-white dark:text-gray-100 bg-indigo-600 dark:bg-gray-800"
- : "text-gray-900 dark:text-gray-300",
- "cursor-default select-none relative py-2 pl-3 pr-9"
- )}
- value={client.id}
- >
- {({ selected, active }) => (
- <>
-
- {client.name}
-
-
- {selected ? (
-
-
-
- ) : null}
- >
- )}
-
- ))}
-
-
-
- >
- )}
-
- )}
-
-
- );
-}
diff --git a/web/src/screens/filters/inputs/MultiSelect.tsx b/web/src/screens/filters/inputs/MultiSelect.tsx
deleted file mode 100644
index 68cf4e8..0000000
--- a/web/src/screens/filters/inputs/MultiSelect.tsx
+++ /dev/null
@@ -1,56 +0,0 @@
-import React from "react";
-import { MultiSelect as RMSC} from "react-multi-select-component";
-import { Field } from "formik";
-import { classNames, COL_WIDTHS } from "../../../styles/utils";
-
-interface Props {
- label?: string;
- options?: [] | any;
- name: string;
- className?: string;
- columns?: COL_WIDTHS;
-}
-
-const MultiSelect: React.FC
= ({
- name,
- label,
- options,
- className,
- columns
-}) => (
-
-
-
-
- {({
- field,
- form: { setFieldValue },
- }: any) => (
- options.find((o: any) => o.value === item))}
- onChange={(values: any) => {
- let am = values && values.map((i: any) => i.value)
-
- setFieldValue(field.name, am)
- }}
- className="dark:bg-gray-700"
- />
- )}
-
-
-);
-
-export default MultiSelect;
\ No newline at end of file
diff --git a/web/src/screens/filters/inputs/NumberField.tsx b/web/src/screens/filters/inputs/NumberField.tsx
deleted file mode 100644
index c94a5a1..0000000
--- a/web/src/screens/filters/inputs/NumberField.tsx
+++ /dev/null
@@ -1,52 +0,0 @@
-import React from "react";
-import { Field } from "formik";
-import { classNames } from "../../../styles/utils";
-
-interface Props {
- name: string;
- label?: string;
- placeholder?: string;
- className?: string;
- required?: boolean;
-}
-
-const NumberField: React.FC = ({
- name,
- label,
- placeholder,
- required,
- className,
-}) => (
-
-
-
-
- {({
- field,
- meta,
- }: any) => (
-
-
- {meta.touched && meta.error && (
-
{meta.error}
- )}
-
-
- )}
-
-
-);
-
-export default NumberField;
diff --git a/web/src/screens/filters/inputs/Select.tsx b/web/src/screens/filters/inputs/Select.tsx
deleted file mode 100644
index 365cc48..0000000
--- a/web/src/screens/filters/inputs/Select.tsx
+++ /dev/null
@@ -1,116 +0,0 @@
-import { Fragment } from "react";
-import { Field } from "formik";
-import { Listbox, Transition } from "@headlessui/react";
-import { CheckIcon, SelectorIcon } from "@heroicons/react/solid";
-import { classNames } from "../../../styles/utils";
-
-interface Option {
- label: string;
- value: string;
-}
-
-interface props {
- name: string;
- label: string;
- optionDefaultText: string;
- options: Option[];
-}
-
-function Select({ name, label, optionDefaultText, options }: props) {
- return (
-
-
- {({
- field,
- form: { setFieldValue },
- }: any) => (
- setFieldValue(field?.name, value)}
- >
- {({ open }) => (
- <>
-
- {label}
-
-
-
-
- {field.value
- ? options.find((c) => c.value === field.value)!.label
- : optionDefaultText
- }
-
-
-
-
-
-
-
-
- {options.map((opt) => (
-
- classNames(
- active
- ? "text-white dark:text-gray-100 bg-indigo-600 dark:bg-gray-800"
- : "text-gray-900 dark:text-gray-300",
- "cursor-default select-none relative py-2 pl-3 pr-9"
- )
- }
- value={opt.value}
- >
- {({ selected, active }) => (
- <>
-
- {opt.label}
-
-
- {selected ? (
-
-
-
- ) : null}
- >
- )}
-
- ))}
-
-
-
- >
- )}
-
- )}
-
-
- );
-}
-
-export default Select;
diff --git a/web/src/screens/filters/inputs/Switch.tsx b/web/src/screens/filters/inputs/Switch.tsx
deleted file mode 100644
index 17fcc55..0000000
--- a/web/src/screens/filters/inputs/Switch.tsx
+++ /dev/null
@@ -1,60 +0,0 @@
-import React, { InputHTMLAttributes } from 'react'
-import { Switch as HeadlessSwitch } from '@headlessui/react'
-import { FieldInputProps, FieldMetaProps, FieldProps, FormikProps, FormikValues } from 'formik'
-import { classNames } from "../../../styles/utils";
-
-type SwitchProps = {
- label: string
- checked: boolean
- disabled?: boolean
- onChange: (value: boolean) => void
- field?: FieldInputProps
- form?: FormikProps
- meta?: FieldMetaProps
-}
-
-export const Switch: React.FC = ({
- label,
- checked: $checked,
- disabled = false,
- onChange: $onChange,
- field,
- form,
-}) => {
- const checked = field?.checked ?? $checked
-
- return (
-
- {label}
- {
- form?.setFieldValue(field?.name ?? '', value)
- $onChange && $onChange(value)
- }}
-
- className={classNames(
- checked ? 'bg-teal-500 dark:bg-blue-500' : 'bg-gray-200 dark:bg-gray-600',
- 'ml-4 relative inline-flex flex-shrink-0 h-6 w-11 border-2 border-transparent rounded-full cursor-pointer transition-colors ease-in-out duration-200 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-blue-500'
- )}
- >
- {({ checked }) => (
-
- )}
-
-
- )
-}
-
-export type SwitchFormikProps = SwitchProps & FieldProps & InputHTMLAttributes
-
-export const SwitchFormik: React.FC = args =>
\ No newline at end of file
diff --git a/web/src/screens/filters/inputs/TextField.tsx b/web/src/screens/filters/inputs/TextField.tsx
deleted file mode 100644
index 443cfdc..0000000
--- a/web/src/screens/filters/inputs/TextField.tsx
+++ /dev/null
@@ -1,51 +0,0 @@
-import React from "react";
-import { Field } from "formik";
-import { classNames } from "../../../styles/utils";
-
-type COL_WIDTHS = 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12;
-
-interface Props {
- name: string;
- label?: string;
- placeholder?: string;
- columns?: COL_WIDTHS;
- className?: string;
- autoComplete?: string;
-}
-
-const TextField: React.FC = ({ name, label, placeholder, columns, className, autoComplete }) => (
-
- {label && (
-
- )}
-
- {({
- field,
- meta,
- }: any) => (
-
-
-
- {meta.touched && meta.error && (
-
{meta.error}
- )}
-
- )}
-
-
-)
-
-export default TextField;
diff --git a/web/src/screens/filters/inputs/index.ts b/web/src/screens/filters/inputs/index.ts
deleted file mode 100644
index 2029573..0000000
--- a/web/src/screens/filters/inputs/index.ts
+++ /dev/null
@@ -1,7 +0,0 @@
-export { default as DownloadClientSelect } from "./DownloadClientSelect";
-export { default as TextField } from "./TextField";
-export { default as Select } from "./Select";
-export { default as SwitchGroup } from "./SwitchGroup";
-export { default as MultiSelect } from "./MultiSelect";
-export { default as NumberField } from "./NumberField";
-export { Switch } from "./Switch";
diff --git a/web/src/screens/filters/list.tsx b/web/src/screens/filters/list.tsx
index e410614..751ca4b 100644
--- a/web/src/screens/filters/list.tsx
+++ b/web/src/screens/filters/list.tsx
@@ -1,6 +1,6 @@
import { useState } from "react";
import { Switch } from "@headlessui/react";
-import { EmptyListState } from "../../components/EmptyListState";
+import { EmptyListState } from "../../components/emptystates";
import {
Link,
@@ -8,7 +8,7 @@ import {
import { Filter } from "../../domain/interfaces";
import { useToggle } from "../../hooks/hooks";
import { useQuery } from "react-query";
-import { classNames } from "../../styles/utils";
+import { classNames } from "../../utils";
import { FilterAddForm } from "../../forms";
import APIClient from "../../api/APIClient";
diff --git a/web/src/screens/settings/Application.tsx b/web/src/screens/settings/Application.tsx
index 8affadf..a9527b8 100644
--- a/web/src/screens/settings/Application.tsx
+++ b/web/src/screens/settings/Application.tsx
@@ -1,17 +1,17 @@
-import React, {useState} from "react";
-import {Switch} from "@headlessui/react";
-import { classNames } from "../../styles/utils";
+import React, { useState } from "react";
+import { Switch } from "@headlessui/react";
+import { classNames } from "../../utils";
// import {useRecoilState} from "recoil";
// import {configState} from "../../state/state";
-import {useQuery} from "react-query";
-import {Config} from "../../domain/interfaces";
+import { useQuery } from "react-query";
+import { Config } from "../../domain/interfaces";
import APIClient from "../../api/APIClient";
function ApplicationSettings() {
const [isDebug, setIsDebug] = useState(true)
// const [config] = useRecoilState(configState)
- const {isLoading, data} = useQuery(['config'], () => APIClient.config.get(),
+ const { isLoading, data } = useQuery(['config'], () => APIClient.config.get(),
{
retry: false,
refetchOnWindowFocus: false,
@@ -33,49 +33,49 @@ function ApplicationSettings() {
{!isLoading && data && (
-
@@ -84,8 +84,7 @@ function ApplicationSettings() {