mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 16:59:12 +00:00
feat(web): mobile UI improvements (#359)
* enhancement: improved alerts component contrast enhancement: simplified and improved radio switch group look fix: fixed inconsistent spacing in input components (there's still some work left to be done) fix: made slideover panel display on full width on mobile devices enhancement: made forms more accessible to mobile users, adapter changes in accordance with the previous input components fix fix: fixed misspelling in NotificationForms filename chore: cleaned up code fix: made filter table top edges less round and improved look fix: fixed a bug where when a modal/slideover component was opened, a 1px white bar would be shown in one of the modal parent elements (for the fix see L89 in screens/settings/DwonloadClient.tsx) enhancement: improved responsiveness for irc network list * Fixed 2 small comma warnings from ESLint Co-authored-by: anonymous <anonymous>
This commit is contained in:
parent
f961115dac
commit
3da594ec75
26 changed files with 758 additions and 640 deletions
|
@ -99,7 +99,7 @@ export const APIClient = {
|
||||||
toggleEnable: (id: number, enabled: boolean) => appClient.Patch(`api/feeds/${id}/enabled`, { enabled }),
|
toggleEnable: (id: number, enabled: boolean) => appClient.Patch(`api/feeds/${id}/enabled`, { enabled }),
|
||||||
update: (feed: Feed) => appClient.Put(`api/feeds/${feed.id}`, feed),
|
update: (feed: Feed) => appClient.Put(`api/feeds/${feed.id}`, feed),
|
||||||
delete: (id: number) => appClient.Delete(`api/feeds/${id}`),
|
delete: (id: number) => appClient.Delete(`api/feeds/${id}`),
|
||||||
test: (feed: Feed) => appClient.Post("api/feeds/test", feed),
|
test: (feed: Feed) => appClient.Post("api/feeds/test", feed)
|
||||||
},
|
},
|
||||||
indexers: {
|
indexers: {
|
||||||
// returns indexer options for all currently present/enabled indexers
|
// returns indexer options for all currently present/enabled indexers
|
||||||
|
|
|
@ -2,30 +2,30 @@
|
||||||
import { ExclamationIcon } from "@heroicons/react/solid";
|
import { ExclamationIcon } from "@heroicons/react/solid";
|
||||||
|
|
||||||
interface props {
|
interface props {
|
||||||
title: string;
|
title?: string;
|
||||||
text: string;
|
text: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function AlertWarning({ title, text }: props) {
|
export function AlertWarning({ title, text }: props) {
|
||||||
return (
|
return (
|
||||||
<div className="p-4">
|
<div className="my-4 rounded-md bg-yellow-50 dark:bg-yellow-100 p-4 border border-yellow-300 dark:border-none">
|
||||||
<div className="rounded-md bg-yellow-50 p-4">
|
|
||||||
<div className="flex">
|
<div className="flex">
|
||||||
<div className="flex-shrink-0">
|
<div className="flex-shrink-0">
|
||||||
<ExclamationIcon
|
<ExclamationIcon
|
||||||
className="h-5 w-5 text-yellow-400"
|
className="h-5 w-5 text-yellow-400 dark:text-yellow-600"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-3">
|
<div className="ml-3">
|
||||||
<h3 className="text-sm font-medium text-yellow-800">{title}</h3>
|
{title ? (
|
||||||
<div className="mt-2 text-sm text-yellow-700">
|
<h3 className="mb-1 text-md font-medium text-yellow-800">{title}</h3>
|
||||||
|
) : null}
|
||||||
|
<div className="text-sm text-yellow-800">
|
||||||
<p>{text}</p>
|
<p>{text}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ const DEBUG: FC<DebugProps> = ({ values }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="w-full p-2 flex flex-col mt-6 bg-gray-100 dark:bg-gray-900">
|
<div className="w-full p-2 flex flex-col mt-6 bg-gray-100 dark:bg-gray-900">
|
||||||
<pre className="dark:text-gray-400">{JSON.stringify(values, null, 2)}</pre>
|
<pre className="dark:text-gray-400 break-all whitespace-pre-wrap">{JSON.stringify(values, null, 2)}</pre>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
|
@ -25,7 +25,7 @@ export const TextFieldWide = ({
|
||||||
required,
|
required,
|
||||||
hidden
|
hidden
|
||||||
}: TextFieldWideProps) => (
|
}: TextFieldWideProps) => (
|
||||||
<div hidden={hidden} className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div hidden={hidden} className="space-y-1 p-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor={name} className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
<label htmlFor={name} className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||||
{label} {required && <span className="text-gray-500">*</span>}
|
{label} {required && <span className="text-gray-500">*</span>}
|
||||||
|
@ -80,7 +80,7 @@ export const PasswordFieldWide = ({
|
||||||
const [isVisible, toggleVisibility] = useToggle(defaultVisible);
|
const [isVisible, toggleVisibility] = useToggle(defaultVisible);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="space-y-1 p-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||||
<div>
|
<div>
|
||||||
<label htmlFor={name} className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
<label htmlFor={name} className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2">
|
||||||
{label} {required && <span className="text-gray-500">*</span>}
|
{label} {required && <span className="text-gray-500">*</span>}
|
||||||
|
@ -134,7 +134,7 @@ export const NumberFieldWide = ({
|
||||||
defaultValue,
|
defaultValue,
|
||||||
required
|
required
|
||||||
}: NumberFieldWideProps) => (
|
}: NumberFieldWideProps) => (
|
||||||
<div className="px-4 space-y-1 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="px-4 space-y-1 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor={name}
|
htmlFor={name}
|
||||||
|
@ -187,7 +187,7 @@ export const SwitchGroupWide = ({
|
||||||
description,
|
description,
|
||||||
defaultValue
|
defaultValue
|
||||||
}: SwitchGroupWideProps) => (
|
}: SwitchGroupWideProps) => (
|
||||||
<ul className="mt-2 divide-y divide-gray-200 dark:divide-gray-700">
|
<ul className="mt-2 px-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<Switch.Group as="li" className="py-4 flex items-center justify-between">
|
<Switch.Group as="li" className="py-4 flex items-center justify-between">
|
||||||
<div className="flex flex-col">
|
<div className="flex flex-col">
|
||||||
<Switch.Label as="p" className="text-sm font-medium text-gray-900 dark:text-white"
|
<Switch.Label as="p" className="text-sm font-medium text-gray-900 dark:text-white"
|
||||||
|
@ -212,7 +212,7 @@ export const SwitchGroupWide = ({
|
||||||
type="button"
|
type="button"
|
||||||
value={field.value}
|
value={field.value}
|
||||||
checked={field.checked ?? false}
|
checked={field.checked ?? false}
|
||||||
onChange={value => {
|
onChange={(value: unknown) => {
|
||||||
form.setFieldValue(field?.name ?? "", value);
|
form.setFieldValue(field?.name ?? "", value);
|
||||||
}}
|
}}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
import { Fragment } from "react";
|
|
||||||
import { Field, useFormikContext } from "formik";
|
import { Field, useFormikContext } from "formik";
|
||||||
import { RadioGroup } from "@headlessui/react";
|
import { RadioGroup } from "@headlessui/react";
|
||||||
import { classNames } from "../../utils";
|
import { classNames } from "../../utils";
|
||||||
|
@ -25,14 +24,13 @@ function RadioFieldsetWide({ name, legend, options }: props) {
|
||||||
setFieldValue
|
setFieldValue
|
||||||
} = useFormikContext<anyObj>();
|
} = useFormikContext<anyObj>();
|
||||||
|
|
||||||
|
|
||||||
const onChange = (value: string) => {
|
const onChange = (value: string) => {
|
||||||
setFieldValue(name, value);
|
setFieldValue(name, value);
|
||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<div className="space-y-2 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:px-6 sm:py-5">
|
<div className="space-y-2 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:items-start sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<legend className="text-sm font-medium text-gray-900 dark:text-white">
|
<legend className="text-sm font-medium text-gray-900 dark:text-white">
|
||||||
{legend}
|
{legend}
|
||||||
|
@ -60,49 +58,41 @@ function RadioFieldsetWide({ name, legend, options }: props) {
|
||||||
? "rounded-bl-md rounded-br-md"
|
? "rounded-bl-md rounded-br-md"
|
||||||
: "",
|
: "",
|
||||||
checked
|
checked
|
||||||
? "bg-indigo-50 dark:bg-gray-700 border-indigo-200 dark:border-blue-600 z-10"
|
? "border-1 bg-indigo-100 dark:bg-blue-900 border-indigo-400 dark:border-blue-600 z-10"
|
||||||
: "border-gray-200 dark:border-gray-700",
|
: "border-gray-200 dark:border-gray-700",
|
||||||
"relative border p-4 flex cursor-pointer focus:outline-none"
|
"relative border p-4 flex cursor-pointer focus:outline-none"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
>
|
>
|
||||||
{({ active, checked }) => (
|
{({ checked }) => (
|
||||||
<Fragment>
|
<>
|
||||||
<span
|
<span
|
||||||
className={classNames(
|
className={classNames(
|
||||||
checked
|
checked
|
||||||
? "bg-indigo-600 dark:bg-blue-600 border-transparent"
|
? "bg-indigo-600 dark:bg-blue-500 border-transparent"
|
||||||
: "bg-white border-gray-300 dark:border-gray-300",
|
: "bg-white dark:bg-gray-800 border-gray-300 dark:border-gray-300",
|
||||||
active
|
"h-6 w-6 mt-1 cursor-pointer rounded-full border flex items-center justify-center"
|
||||||
? "ring-2 ring-offset-2 ring-indigo-500 dark:ring-blue-500"
|
|
||||||
: "",
|
|
||||||
"h-4 w-4 mt-0.5 cursor-pointer rounded-full border flex items-center justify-center"
|
|
||||||
)}
|
)}
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
>
|
/>
|
||||||
<span className="rounded-full bg-white w-1.5 h-1.5" />
|
|
||||||
</span>
|
|
||||||
<div className="ml-3 flex flex-col">
|
<div className="ml-3 flex flex-col">
|
||||||
<RadioGroup.Label
|
<RadioGroup.Label
|
||||||
as="span"
|
as="span"
|
||||||
className={classNames(
|
className={classNames(
|
||||||
checked ? "text-indigo-900 dark:text-blue-500" : "text-gray-900 dark:text-gray-300",
|
"block text-md text-gray-900 dark:text-gray-300",
|
||||||
"block text-sm font-medium"
|
checked ? "font-bold" : "font-medium"
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{setting.label}
|
{setting.label}
|
||||||
</RadioGroup.Label>
|
</RadioGroup.Label>
|
||||||
<RadioGroup.Description
|
<RadioGroup.Description
|
||||||
as="span"
|
as="span"
|
||||||
className={classNames(
|
className="block text-sm text-gray-700 dark:text-gray-400"
|
||||||
checked ? "text-indigo-700 dark:text-blue-500" : "text-gray-500",
|
|
||||||
"block text-sm"
|
|
||||||
)}
|
|
||||||
>
|
>
|
||||||
{setting.description}
|
{setting.description}
|
||||||
</RadioGroup.Description>
|
</RadioGroup.Description>
|
||||||
</div>
|
</div>
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</RadioGroup.Option>
|
</RadioGroup.Option>
|
||||||
))}
|
))}
|
||||||
|
|
|
@ -354,7 +354,7 @@ export const SelectWide = ({
|
||||||
return (
|
return (
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||||
|
|
||||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<Field name={name} type="select">
|
<Field name={name} type="select">
|
||||||
{({
|
{({
|
||||||
field,
|
field,
|
||||||
|
|
|
@ -36,7 +36,7 @@ function SlideOver<DataType>({
|
||||||
testFn,
|
testFn,
|
||||||
isTesting,
|
isTesting,
|
||||||
isTestSuccessful,
|
isTestSuccessful,
|
||||||
isTestError,
|
isTestError
|
||||||
}: SlideOverProps<DataType>): React.ReactElement {
|
}: SlideOverProps<DataType>): React.ReactElement {
|
||||||
const cancelModalButtonRef = useRef<HTMLInputElement | null>(null);
|
const cancelModalButtonRef = useRef<HTMLInputElement | null>(null);
|
||||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
|
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
|
||||||
|
@ -64,7 +64,7 @@ function SlideOver<DataType>({
|
||||||
<div className="absolute inset-0 overflow-hidden">
|
<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">
|
<div className="fixed inset-y-0 right-0 max-w-full flex">
|
||||||
<Transition.Child
|
<Transition.Child
|
||||||
as={Fragment}
|
as={Fragment}
|
||||||
enter="transform transition ease-in-out duration-500 sm:duration-700"
|
enter="transform transition ease-in-out duration-500 sm:duration-700"
|
||||||
|
|
|
@ -338,5 +338,5 @@ export const EventOptions: SelectOption[] = [
|
||||||
label: "New update",
|
label: "New update",
|
||||||
value: "APP_UPDATE_AVAILABLE",
|
value: "APP_UPDATE_AVAILABLE",
|
||||||
description: "Get notified on updates"
|
description: "Get notified on updates"
|
||||||
},
|
}
|
||||||
];
|
];
|
||||||
|
|
|
@ -96,7 +96,7 @@ function FilterAddForm({ isOpen, toggle }: filterAddFormProps) {
|
||||||
<div
|
<div
|
||||||
className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||||
<div
|
<div
|
||||||
className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="name"
|
htmlFor="name"
|
||||||
|
|
|
@ -50,24 +50,31 @@ function FormFieldsDefault() {
|
||||||
} = useFormikContext<InitialValues>();
|
} = useFormikContext<InitialValues>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="host" label="Host" help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port"/>
|
<TextFieldWide
|
||||||
|
name="host"
|
||||||
|
label="Host"
|
||||||
|
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port"
|
||||||
|
/>
|
||||||
|
|
||||||
<NumberFieldWide name="port" label="Port" help="WebUI port for qBittorrent and daemon port for Deluge"/>
|
<NumberFieldWide
|
||||||
|
name="port"
|
||||||
|
label="Port"
|
||||||
|
help="WebUI port for qBittorrent and daemon port for Deluge"
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="tls" label="TLS" />
|
<SwitchGroupWide name="tls" label="TLS" />
|
||||||
|
|
||||||
{tls && (
|
{tls && (
|
||||||
<Fragment>
|
<SwitchGroupWide
|
||||||
<SwitchGroupWide name="tls_skip_verify" label="Skip TLS verification (insecure)"/>
|
name="tls_skip_verify"
|
||||||
</Fragment>
|
label="Skip TLS verification (insecure)"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
<TextFieldWide name="username" label="Username" />
|
<TextFieldWide name="username" label="Username" />
|
||||||
<PasswordFieldWide name="password" label="Password" />
|
<PasswordFieldWide name="password" label="Password" />
|
||||||
</Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -77,22 +84,24 @@ function FormFieldsArr() {
|
||||||
} = useFormikContext<InitialValues>();
|
} = useFormikContext<InitialValues>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<div className="flex flex-col space-y-4 px-1 mb-4 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="host" label="Host" help="Full url http(s)://domain.ltd and/or subdomain/subfolder"/>
|
<TextFieldWide
|
||||||
|
name="host"
|
||||||
|
label="Host"
|
||||||
|
help="Full url http(s)://domain.ltd and/or subdomain/subfolder"
|
||||||
|
/>
|
||||||
|
|
||||||
<PasswordFieldWide name="settings.apikey" label="API key" />
|
<PasswordFieldWide name="settings.apikey" label="API key" />
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="settings.basic.auth" label="Basic auth" />
|
<SwitchGroupWide name="settings.basic.auth" label="Basic auth" />
|
||||||
</div>
|
|
||||||
|
|
||||||
{settings.basic?.auth === true && (
|
{settings.basic?.auth === true && (
|
||||||
<Fragment>
|
<>
|
||||||
<TextFieldWide name="settings.basic.username" label="Username" />
|
<TextFieldWide name="settings.basic.username" label="Username" />
|
||||||
<PasswordFieldWide name="settings.basic.password" label="Password" />
|
<PasswordFieldWide name="settings.basic.password" label="Password" />
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,37 +111,42 @@ function FormFieldsQbit() {
|
||||||
} = useFormikContext<InitialValues>();
|
} = useFormikContext<InitialValues>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="host" label="Host" help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port" />
|
<TextFieldWide
|
||||||
|
name="host"
|
||||||
|
label="Host"
|
||||||
|
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd:port"
|
||||||
|
/>
|
||||||
|
|
||||||
{port > 0 && (
|
{port > 0 && (
|
||||||
<NumberFieldWide name="port" label="Port" help="WebUI port for qBittorrent" />
|
<NumberFieldWide
|
||||||
|
name="port"
|
||||||
|
label="Port"
|
||||||
|
help="WebUI port for qBittorrent"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="tls" label="TLS" />
|
<SwitchGroupWide name="tls" label="TLS" />
|
||||||
|
|
||||||
{tls && (
|
{tls && (
|
||||||
<Fragment>
|
<SwitchGroupWide
|
||||||
<SwitchGroupWide name="tls_skip_verify" label="Skip TLS verification (insecure)" />
|
name="tls_skip_verify"
|
||||||
</Fragment>
|
label="Skip TLS verification (insecure)"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
<TextFieldWide name="username" label="Username" />
|
<TextFieldWide name="username" label="Username" />
|
||||||
<PasswordFieldWide name="password" label="Password" />
|
<PasswordFieldWide name="password" label="Password" />
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="settings.basic.auth" label="Basic auth" />
|
<SwitchGroupWide name="settings.basic.auth" label="Basic auth" />
|
||||||
</div>
|
|
||||||
|
|
||||||
{settings.basic?.auth === true && (
|
{settings.basic?.auth === true && (
|
||||||
<Fragment>
|
<>
|
||||||
<TextFieldWide name="settings.basic.username" label="Username" />
|
<TextFieldWide name="settings.basic.username" label="Username" />
|
||||||
<PasswordFieldWide name="settings.basic.password" label="Password" />
|
<PasswordFieldWide name="settings.basic.password" label="Password" />
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -142,24 +156,27 @@ function FormFieldsTransmission() {
|
||||||
} = useFormikContext<InitialValues>();
|
} = useFormikContext<InitialValues>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Fragment>
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="host" label="Host" help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd"/>
|
<TextFieldWide
|
||||||
|
name="host"
|
||||||
|
label="Host"
|
||||||
|
help="Eg. client.domain.ltd, domain.ltd/client, domain.ltd"
|
||||||
|
/>
|
||||||
|
|
||||||
<NumberFieldWide name="port" label="Port" help="Port for Transmission" />
|
<NumberFieldWide name="port" label="Port" help="Port for Transmission" />
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="tls" label="TLS" />
|
<SwitchGroupWide name="tls" label="TLS" />
|
||||||
|
|
||||||
{tls && (
|
{tls && (
|
||||||
<Fragment>
|
<SwitchGroupWide
|
||||||
<SwitchGroupWide name="tls_skip_verify" label="Skip TLS verification (insecure)"/>
|
name="tls_skip_verify"
|
||||||
</Fragment>
|
label="Skip TLS verification (insecure)"
|
||||||
|
/>
|
||||||
)}
|
)}
|
||||||
</div>
|
|
||||||
|
|
||||||
<TextFieldWide name="username" label="Username" />
|
<TextFieldWide name="username" label="Username" />
|
||||||
<PasswordFieldWide name="password" label="Password" />
|
<PasswordFieldWide name="password" label="Password" />
|
||||||
</Fragment>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -186,21 +203,17 @@ function FormFieldsRulesBasic() {
|
||||||
return (
|
return (
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
||||||
|
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Rules</Dialog.Title>
|
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Rules</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Manage max downloads.
|
Manage max downloads.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="settings.rules.enabled" label="Enabled"/>
|
<SwitchGroupWide name="settings.rules.enabled" label="Enabled"/>
|
||||||
</div>
|
|
||||||
|
|
||||||
{settings && settings.rules?.enabled === true && (
|
{settings && settings.rules?.enabled === true && (
|
||||||
<Fragment>
|
|
||||||
<NumberFieldWide name="settings.rules.max_active_downloads" label="Max active downloads"/>
|
<NumberFieldWide name="settings.rules.max_active_downloads" label="Max active downloads"/>
|
||||||
</Fragment>
|
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -212,34 +225,38 @@ function FormFieldsRules() {
|
||||||
} = useFormikContext<InitialValues>();
|
} = useFormikContext<InitialValues>();
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t border-gray-200 dark:border-gray-700 py-5 px-2">
|
||||||
|
<div className="px-4 space-y-1">
|
||||||
<div className="px-6 space-y-1">
|
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Rules</Dialog.Title>
|
Rules
|
||||||
|
</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Manage max downloads etc.
|
Manage max downloads etc.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="settings.rules.enabled" label="Enabled" />
|
<SwitchGroupWide name="settings.rules.enabled" label="Enabled" />
|
||||||
</div>
|
|
||||||
|
|
||||||
{settings.rules?.enabled === true && (
|
{settings.rules?.enabled === true && (
|
||||||
<Fragment>
|
<>
|
||||||
<NumberFieldWide name="settings.rules.max_active_downloads" label="Max active downloads"/>
|
<NumberFieldWide
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
name="settings.rules.max_active_downloads"
|
||||||
<SwitchGroupWide name="settings.rules.ignore_slow_torrents" label="Ignore slow torrents"/>
|
label="Max active downloads"
|
||||||
</div>
|
/>
|
||||||
|
<SwitchGroupWide
|
||||||
|
name="settings.rules.ignore_slow_torrents"
|
||||||
|
label="Ignore slow torrents"
|
||||||
|
/>
|
||||||
|
|
||||||
{settings.rules?.ignore_slow_torrents === true && (
|
{settings.rules?.ignore_slow_torrents === true && (
|
||||||
<Fragment>
|
<NumberFieldWide
|
||||||
<NumberFieldWide name="settings.rules.download_speed_threshold" label="Download speed threshold"
|
name="settings.rules.download_speed_threshold"
|
||||||
|
label="Download speed threshold"
|
||||||
placeholder="in KB/s"
|
placeholder="in KB/s"
|
||||||
help="If download speed is below this when max active downloads is hit, download anyways. KB/s"/>
|
help="If download speed is below this when max active downloads is hit, download anyways. KB/s"
|
||||||
</Fragment>
|
/>
|
||||||
)}
|
)}
|
||||||
</Fragment>
|
</>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -248,7 +265,7 @@ function FormFieldsRules() {
|
||||||
export const rulesComponentMap: componentMapType = {
|
export const rulesComponentMap: componentMapType = {
|
||||||
DELUGE_V1: <FormFieldsRulesBasic/>,
|
DELUGE_V1: <FormFieldsRulesBasic/>,
|
||||||
DELUGE_V2: <FormFieldsRulesBasic/>,
|
DELUGE_V2: <FormFieldsRulesBasic/>,
|
||||||
QBITTORRENT: <FormFieldsRules/>,
|
QBITTORRENT: <FormFieldsRules/>
|
||||||
};
|
};
|
||||||
|
|
||||||
interface formButtonsProps {
|
interface formButtonsProps {
|
||||||
|
@ -490,20 +507,14 @@ export function DownloadClientAddForm({ isOpen, toggle }: formProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y dark:divide-gray-700">
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="name" label="Name"/>
|
<TextFieldWide name="name" label="Name"/>
|
||||||
|
|
||||||
<div
|
|
||||||
className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<RadioFieldsetWide
|
<RadioFieldsetWide
|
||||||
name="type"
|
name="type"
|
||||||
legend="Type"
|
legend="Type"
|
||||||
options={DownloadClientTypeOptions}
|
options={DownloadClientTypeOptions}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div>{componentMap[values.type]}</div>
|
<div>{componentMap[values.type]}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -697,17 +708,12 @@ export function DownloadClientUpdateForm({ client, isOpen, toggle }: updateFormP
|
||||||
|
|
||||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y dark:divide-gray-700">
|
<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"/>
|
<TextFieldWide name="name" label="Name"/>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||||
</div>
|
|
||||||
|
|
||||||
<RadioFieldsetWide
|
<RadioFieldsetWide
|
||||||
name="type"
|
name="type"
|
||||||
legend="Type"
|
legend="Type"
|
||||||
options={DownloadClientTypeOptions}
|
options={DownloadClientTypeOptions}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div>{componentMap[values.type]}</div>
|
<div>{componentMap[values.type]}</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -116,7 +116,7 @@ export function FeedUpdateForm({ isOpen, toggle, feed }: UpdateProps) {
|
||||||
|
|
||||||
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<div
|
<div
|
||||||
className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="type"
|
htmlFor="type"
|
||||||
|
|
|
@ -63,7 +63,7 @@ const IrcSettingFields = (ind: IndexerDefinition, indexer: string) => {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{ind && ind.irc && ind.irc.settings && (
|
{ind && ind.irc && ind.irc.settings && (
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">IRC</Dialog.Title>
|
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">IRC</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-200">
|
<p className="text-sm text-gray-500 dark:text-gray-200">
|
||||||
Networks, channels and invite commands are configured automatically.
|
Networks, channels and invite commands are configured automatically.
|
||||||
|
@ -94,7 +94,7 @@ const FeedSettingFields = (ind: IndexerDefinition, indexer: string) => {
|
||||||
<Fragment>
|
<Fragment>
|
||||||
{ind && ind.torznab && ind.torznab.settings && (
|
{ind && ind.torznab && ind.torznab.settings && (
|
||||||
<div className="">
|
<div className="">
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Torznab</Dialog.Title>
|
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Torznab</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-200">
|
<p className="text-sm text-gray-500 dark:text-gray-200">
|
||||||
Torznab feed
|
Torznab feed
|
||||||
|
@ -329,7 +329,7 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="py-6 space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="identifier"
|
htmlFor="identifier"
|
||||||
|
@ -391,9 +391,7 @@ export function IndexerAddForm({ isOpen, toggle }: AddProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||||
</div>
|
|
||||||
|
|
||||||
{SettingFields(indexer, values.identifier)}
|
{SettingFields(indexer, values.identifier)}
|
||||||
|
|
||||||
|
@ -519,16 +517,14 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
|
||||||
initialValues={initialValues}
|
initialValues={initialValues}
|
||||||
>
|
>
|
||||||
{() => (
|
{() => (
|
||||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="py-2 space-y-6 sm:py-0 sm:space-y-0 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="space-y-1 p-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||||
<div>
|
|
||||||
<label
|
<label
|
||||||
htmlFor="name"
|
htmlFor="name"
|
||||||
className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2"
|
className="block text-sm font-medium text-gray-900 dark:text-white sm:mt-px sm:pt-2"
|
||||||
>
|
>
|
||||||
Name
|
Name
|
||||||
</label>
|
</label>
|
||||||
</div>
|
|
||||||
<Field name="name">
|
<Field name="name">
|
||||||
{({ field, meta }: FieldProps) => (
|
{({ field, meta }: FieldProps) => (
|
||||||
<div className="sm:col-span-2">
|
<div className="sm:col-span-2">
|
||||||
|
@ -542,11 +538,7 @@ export function IndexerUpdateForm({ isOpen, toggle, indexer }: UpdateProps) {
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:sm:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||||
</div>
|
|
||||||
|
|
||||||
{renderSettingFields(indexer.settings)}
|
{renderSettingFields(indexer.settings)}
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -24,7 +24,7 @@ const ChannelsFieldArray = ({ channels }: ChannelsFieldArrayProps) => (
|
||||||
<div className="p-6">
|
<div className="p-6">
|
||||||
<FieldArray name="channels">
|
<FieldArray name="channels">
|
||||||
{({ remove, push }) => (
|
{({ remove, push }) => (
|
||||||
<div className="flex flex-col border-2 border-dashed dark:border-gray-700 p-4">
|
<div className="flex flex-col space-y-2 border-2 border-dashed dark:border-gray-700 p-4">
|
||||||
{channels && channels.length > 0 ? (
|
{channels && channels.length > 0 ? (
|
||||||
channels.map((_channel: IrcChannel, index: number) => (
|
channels.map((_channel: IrcChannel, index: number) => (
|
||||||
<div key={index} className="flex justify-between">
|
<div key={index} className="flex justify-between">
|
||||||
|
@ -159,34 +159,47 @@ export function IrcNetworkAddForm({ isOpen, toggle }: AddFormProps) {
|
||||||
validate={validate}
|
validate={validate}
|
||||||
>
|
>
|
||||||
{(values) => (
|
{(values) => (
|
||||||
<>
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="name" label="Name" placeholder="Name" required={true} />
|
<TextFieldWide
|
||||||
|
name="name"
|
||||||
|
label="Name"
|
||||||
|
placeholder="Name"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y dark:divide-gray-700">
|
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200 dark:sm:divide-gray-700">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||||
</div>
|
<TextFieldWide
|
||||||
|
name="server"
|
||||||
<div>
|
label="Server"
|
||||||
<TextFieldWide name="server" label="Server" placeholder="Address: Eg irc.server.net" required={true} />
|
placeholder="Address: Eg irc.server.net"
|
||||||
<NumberFieldWide name="port" label="Port" placeholder="Eg 6667" required={true} />
|
required={true}
|
||||||
|
/>
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
<NumberFieldWide
|
||||||
|
name="port"
|
||||||
|
label="Port"
|
||||||
|
placeholder="Eg 6667"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
<SwitchGroupWide name="tls" label="TLS" />
|
<SwitchGroupWide name="tls" label="TLS" />
|
||||||
</div>
|
<PasswordFieldWide
|
||||||
|
name="pass"
|
||||||
<PasswordFieldWide name="pass" label="Password" help="Network password" />
|
label="Password"
|
||||||
|
help="Network password"
|
||||||
<TextFieldWide name="nickserv.account" label="NickServ Account" placeholder="NickServ Account" required={true} />
|
/>
|
||||||
<PasswordFieldWide name="nickserv.password" label="NickServ Password" />
|
<TextFieldWide
|
||||||
|
name="nickserv.account"
|
||||||
|
label="NickServ Account"
|
||||||
|
placeholder="NickServ Account"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
<PasswordFieldWide
|
||||||
|
name="nickserv.password"
|
||||||
|
label="NickServ Password"
|
||||||
|
/>
|
||||||
<PasswordFieldWide name="invite_command" label="Invite command" />
|
<PasswordFieldWide name="invite_command" label="Invite command" />
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ChannelsFieldArray channels={values.channels} />
|
<ChannelsFieldArray channels={values.channels} />
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</SlideOver>
|
</SlideOver>
|
||||||
);
|
);
|
||||||
|
@ -290,34 +303,51 @@ export function IrcNetworkUpdateForm({
|
||||||
validate={validate}
|
validate={validate}
|
||||||
>
|
>
|
||||||
{(values) => (
|
{(values) => (
|
||||||
<>
|
<div className="flex flex-col space-y-4 px-1 py-6 sm:py-0 sm:space-y-0">
|
||||||
<TextFieldWide name="name" label="Name" placeholder="Name" required={true} />
|
<TextFieldWide
|
||||||
|
name="name"
|
||||||
|
label="Name"
|
||||||
|
placeholder="Name"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y dark:divide-gray-700">
|
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||||
</div>
|
<TextFieldWide
|
||||||
|
name="server"
|
||||||
|
label="Server"
|
||||||
|
placeholder="Address: Eg irc.server.net"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
<NumberFieldWide
|
||||||
|
name="port"
|
||||||
|
label="Port"
|
||||||
|
placeholder="Eg 6667"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
|
||||||
<div>
|
|
||||||
<TextFieldWide name="server" label="Server" placeholder="Address: Eg irc.server.net" required={true} />
|
|
||||||
<NumberFieldWide name="port" label="Port" placeholder="Eg 6667" required={true} />
|
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="tls" label="TLS" />
|
<SwitchGroupWide name="tls" label="TLS" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<PasswordFieldWide name="pass" label="Password" help="Network password" />
|
<PasswordFieldWide
|
||||||
|
name="pass"
|
||||||
|
label="Password"
|
||||||
|
help="Network password"
|
||||||
|
/>
|
||||||
|
|
||||||
<TextFieldWide name="nickserv.account" label="NickServ Account" placeholder="NickServ Account" required={true} />
|
<TextFieldWide
|
||||||
<PasswordFieldWide name="nickserv.password" label="NickServ Password" />
|
name="nickserv.account"
|
||||||
|
label="NickServ Account"
|
||||||
|
placeholder="NickServ Account"
|
||||||
|
required={true}
|
||||||
|
/>
|
||||||
|
<PasswordFieldWide
|
||||||
|
name="nickserv.password"
|
||||||
|
label="NickServ Password"
|
||||||
|
/>
|
||||||
|
|
||||||
<PasswordFieldWide name="invite_command" label="Invite command" />
|
<PasswordFieldWide name="invite_command" label="Invite command" />
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<ChannelsFieldArray channels={values.channels} />
|
<ChannelsFieldArray channels={values.channels} />
|
||||||
</>
|
</div>
|
||||||
)}
|
)}
|
||||||
</SlideOver>
|
</SlideOver>
|
||||||
);
|
);
|
||||||
|
|
|
@ -62,11 +62,11 @@ const Option = (props: OptionProps) => {
|
||||||
|
|
||||||
function FormFieldsDiscord() {
|
function FormFieldsDiscord() {
|
||||||
return (
|
return (
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t border-gray-200 dark:border-gray-700 py-4">
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
|
<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">
|
<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">webhook integration</a> in your server.
|
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.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -82,11 +82,11 @@ function FormFieldsDiscord() {
|
||||||
|
|
||||||
function FormFieldsTelegram() {
|
function FormFieldsTelegram() {
|
||||||
return (
|
return (
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t border-gray-200 dark:border-gray-700 py-4">
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">Settings</Dialog.Title>
|
<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">
|
<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">create a bot</a>.
|
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>.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -161,7 +161,13 @@ export function NotificationAddForm({ isOpen, toggle }: AddProps) {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Transition.Root show={isOpen} as={Fragment}>
|
<Transition.Root show={isOpen} as={Fragment}>
|
||||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden" open={isOpen} onClose={toggle}>
|
<Dialog
|
||||||
|
as="div"
|
||||||
|
static
|
||||||
|
className="fixed inset-0 overflow-hidden"
|
||||||
|
open={isOpen}
|
||||||
|
onClose={toggle}
|
||||||
|
>
|
||||||
<div className="absolute inset-0 overflow-hidden">
|
<div className="absolute inset-0 overflow-hidden">
|
||||||
<Dialog.Overlay className="absolute inset-0" />
|
<Dialog.Overlay className="absolute inset-0" />
|
||||||
|
|
||||||
|
@ -214,10 +220,14 @@ export function NotificationAddForm({ isOpen, toggle }: AddProps) {
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<TextFieldWide name="name" label="Name" required={true}/>
|
<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}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4">
|
||||||
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="type"
|
htmlFor="type"
|
||||||
|
@ -232,10 +242,16 @@ export function NotificationAddForm({ isOpen, toggle }: AddProps) {
|
||||||
field,
|
field,
|
||||||
form: { setFieldValue, resetForm }
|
form: { setFieldValue, resetForm }
|
||||||
}: FieldProps) => (
|
}: FieldProps) => (
|
||||||
<Select {...field}
|
<Select
|
||||||
|
{...field}
|
||||||
isClearable={true}
|
isClearable={true}
|
||||||
isSearchable={true}
|
isSearchable={true}
|
||||||
components={{ Input, Control, Menu, Option }}
|
components={{
|
||||||
|
Input,
|
||||||
|
Control,
|
||||||
|
Menu,
|
||||||
|
Option
|
||||||
|
}}
|
||||||
placeholder="Choose a type"
|
placeholder="Choose a type"
|
||||||
styles={{
|
styles={{
|
||||||
singleValue: (base) => ({
|
singleValue: (base) => ({
|
||||||
|
@ -257,39 +273,39 @@ export function NotificationAddForm({ isOpen, toggle }: AddProps) {
|
||||||
|
|
||||||
const opt = option as SelectOption;
|
const opt = option as SelectOption;
|
||||||
// setFieldValue("name", option?.label ?? "")
|
// setFieldValue("name", option?.label ?? "")
|
||||||
setFieldValue(field.name, opt.value ?? "");
|
setFieldValue(
|
||||||
|
field.name,
|
||||||
|
opt.value ?? ""
|
||||||
|
);
|
||||||
}}
|
}}
|
||||||
options={NotificationTypeOptions}
|
options={NotificationTypeOptions}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</Field>
|
</Field>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled" />
|
<SwitchGroupWide name="enabled" label="Enabled" />
|
||||||
</div>
|
|
||||||
|
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
<div className="border-t mt-2 border-gray-200 dark:border-gray-700 py-4">
|
||||||
<div className="px-6 space-y-1">
|
<div className="px-4 space-y-1">
|
||||||
<Dialog.Title
|
<Dialog.Title className="text-lg font-medium text-gray-900 dark:text-white">
|
||||||
className="text-lg font-medium text-gray-900 dark:text-white">Events</Dialog.Title>
|
Events
|
||||||
|
</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
Select what events to trigger on
|
Select what events to trigger on
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:px-6 sm:py-5">
|
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:py-4">
|
||||||
<EventCheckBoxes />
|
<EventCheckBoxes />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
{componentMap[values.type]}
|
{componentMap[values.type]}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="flex-shrink-0 px-4 border-t border-gray-200 dark:border-gray-700 py-5 sm:px-6">
|
<div className="flex-shrink-0 px-4 border-t border-gray-200 dark:border-gray-700 py-4 sm:px-6">
|
||||||
<div className="space-x-3 flex justify-end">
|
<div className="space-x-3 flex justify-end">
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
|
@ -319,7 +335,6 @@ export function NotificationAddForm({ isOpen, toggle }: AddProps) {
|
||||||
)}
|
)}
|
||||||
</Formik>
|
</Formik>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</Transition.Child>
|
</Transition.Child>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -432,8 +447,8 @@ export function NotificationUpdateForm({ isOpen, toggle, notification }: UpdateP
|
||||||
<div>
|
<div>
|
||||||
<TextFieldWide name="name" label="Name" required={true}/>
|
<TextFieldWide name="name" label="Name" required={true}/>
|
||||||
|
|
||||||
<div className="space-y-4 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="space-y-2 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-6 sm:py-5">
|
<div className="py-4 flex items-center justify-between space-y-1 px-4 sm:space-y-0 sm:grid sm:grid-cols-3 sm:gap-4 sm:py-4">
|
||||||
<div>
|
<div>
|
||||||
<label
|
<label
|
||||||
htmlFor="type"
|
htmlFor="type"
|
||||||
|
@ -477,13 +492,9 @@ export function NotificationUpdateForm({ isOpen, toggle, notification }: UpdateP
|
||||||
</Field>
|
</Field>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
|
||||||
<SwitchGroupWide name="enabled" label="Enabled"/>
|
<SwitchGroupWide name="enabled" label="Enabled"/>
|
||||||
</div>
|
<div className="border-t border-gray-200 dark:border-gray-700 py-4">
|
||||||
|
<div className="px-4 space-y-1">
|
||||||
<div className="border-t border-gray-200 dark:border-gray-700 py-5">
|
|
||||||
<div className="px-6 space-y-1">
|
|
||||||
<Dialog.Title
|
<Dialog.Title
|
||||||
className="text-lg font-medium text-gray-900 dark:text-white">Events</Dialog.Title>
|
className="text-lg font-medium text-gray-900 dark:text-white">Events</Dialog.Title>
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
<p className="text-sm text-gray-500 dark:text-gray-400">
|
||||||
|
@ -491,7 +502,7 @@ export function NotificationUpdateForm({ isOpen, toggle, notification }: UpdateP
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:px-6 sm:py-5">
|
<div className="space-y-1 px-4 sm:space-y-0 sm:grid sm:gap-4 sm:py-2">
|
||||||
<EventCheckBoxes />
|
<EventCheckBoxes />
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
|
@ -46,7 +46,7 @@ function SubNavLink({ item }: NavLinkProps) {
|
||||||
className={({ isActive }) => classNames(
|
className={({ isActive }) => classNames(
|
||||||
"border-transparent text-gray-900 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-300 group border-l-4 px-3 py-2 flex items-center text-sm font-medium",
|
"border-transparent text-gray-900 dark:text-gray-200 hover:bg-gray-50 dark:hover:bg-gray-700 hover:text-gray-900 dark:hover:text-gray-300 group border-l-4 px-3 py-2 flex items-center text-sm font-medium",
|
||||||
isActive ?
|
isActive ?
|
||||||
"bg-teal-50 dark:bg-gray-700 border-teal-500 dark:border-blue-500 text-teal-700 dark:text-white hover:bg-teal-50 dark:hover:bg-gray-500 hover:text-teal-700 dark:hover:text-gray-200" : ""
|
"font-bold bg-teal-50 dark:bg-gray-700 border-teal-500 dark:border-blue-500 text-teal-700 dark:text-white hover:bg-teal-50 dark:hover:bg-gray-500 hover:text-teal-700 dark:hover:text-gray-200" : ""
|
||||||
)}
|
)}
|
||||||
aria-current={splitLocation[2] === item.href ? "page" : undefined}
|
aria-current={splitLocation[2] === item.href ? "page" : undefined}
|
||||||
>
|
>
|
||||||
|
|
|
@ -609,25 +609,17 @@ export function FilterActions({ filter, values }: FilterActionsProps) {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
interface FilterActionsItemProps {
|
interface TypeFormProps {
|
||||||
action: Action;
|
action: Action;
|
||||||
clients: DownloadClient[];
|
|
||||||
idx: number;
|
idx: number;
|
||||||
remove: <T>(index: number) => T | undefined;
|
clients: Array<DownloadClient>;
|
||||||
}
|
}
|
||||||
|
|
||||||
function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemProps) {
|
const TypeForm = ({ action, idx, clients }: TypeFormProps) => {
|
||||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
|
switch (action.type) {
|
||||||
const [edit, toggleEdit] = useToggle(false);
|
|
||||||
|
|
||||||
const cancelButtonRef = useRef(null);
|
|
||||||
|
|
||||||
const TypeForm = (actionType: ActionType) => {
|
|
||||||
switch (actionType) {
|
|
||||||
case "TEST":
|
case "TEST":
|
||||||
return (
|
return (
|
||||||
<AlertWarning
|
<AlertWarning
|
||||||
title="Notice"
|
|
||||||
text="The test action does nothing except to show if the filter works."
|
text="The test action does nothing except to show if the filter works."
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
@ -699,8 +691,18 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="mt-6 grid grid-cols-12 gap-6">
|
<div className="mt-6 grid grid-cols-12 gap-6">
|
||||||
<TextField name={`actions.${idx}.category`} label="Category" columns={6} placeholder="eg. category" />
|
<TextField
|
||||||
<TextField name={`actions.${idx}.tags`} label="Tags" columns={6} placeholder="eg. tag1,tag2" />
|
name={`actions.${idx}.category`}
|
||||||
|
label="Category"
|
||||||
|
columns={6}
|
||||||
|
placeholder="eg. category"
|
||||||
|
/>
|
||||||
|
<TextField
|
||||||
|
name={`actions.${idx}.tags`}
|
||||||
|
label="Tags"
|
||||||
|
columns={6}
|
||||||
|
placeholder="eg. tag1,tag2"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<CollapsableSection title="Rules" subtitle="client options">
|
<CollapsableSection title="Rules" subtitle="client options">
|
||||||
|
@ -867,6 +869,19 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
interface FilterActionsItemProps {
|
||||||
|
action: Action;
|
||||||
|
clients: DownloadClient[];
|
||||||
|
idx: number;
|
||||||
|
remove: <T>(index: number) => T | undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemProps) {
|
||||||
|
const cancelButtonRef = useRef(null);
|
||||||
|
|
||||||
|
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false);
|
||||||
|
const [edit, toggleEdit] = useToggle(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<li>
|
<li>
|
||||||
<div
|
<div
|
||||||
|
@ -966,7 +981,7 @@ function FilterActionsItem({ action, clients, idx, remove }: FilterActionsItemPr
|
||||||
<TextField name={`actions.${idx}.name`} label="Name" columns={6} />
|
<TextField name={`actions.${idx}.name`} label="Name" columns={6} />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{TypeForm(action.type)}
|
<TypeForm action={action} clients={clients} idx={idx} />
|
||||||
|
|
||||||
<div className="pt-6 divide-y divide-gray-200">
|
<div className="pt-6 divide-y divide-gray-200">
|
||||||
<div className="mt-4 pt-4 flex justify-between">
|
<div className="mt-4 pt-4 flex justify-between">
|
||||||
|
|
|
@ -72,7 +72,7 @@ interface FilterListProps {
|
||||||
|
|
||||||
function FilterList({ filters }: FilterListProps) {
|
function FilterList({ filters }: FilterListProps) {
|
||||||
return (
|
return (
|
||||||
<div className="overflow-x-auto align-middle min-w-full rounded-lg shadow-lg">
|
<div className="overflow-x-auto align-middle min-w-full rounded-t-md rounded-b-lg shadow-lg">
|
||||||
<table className="min-w-full">
|
<table className="min-w-full">
|
||||||
<thead className="bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
|
<thead className="bg-gray-50 dark:bg-gray-800 text-gray-500 dark:text-gray-400 border-b border-gray-200 dark:border-gray-700">
|
||||||
<tr>
|
<tr>
|
||||||
|
@ -80,7 +80,7 @@ function FilterList({ filters }: FilterListProps) {
|
||||||
<th
|
<th
|
||||||
key={`th-${label}`}
|
key={`th-${label}`}
|
||||||
scope="col"
|
scope="col"
|
||||||
className="px-6 py-2.5 text-left text-xs font-medium uppercase tracking-wider"
|
className="px-6 pt-4 pb-3 text-left text-xs font-medium uppercase tracking-wider"
|
||||||
>
|
>
|
||||||
{label}
|
{label}
|
||||||
</th>
|
</th>
|
||||||
|
|
|
@ -1,12 +1,7 @@
|
||||||
function ActionSettings() {
|
function ActionSettings() {
|
||||||
return (
|
return (
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
<div className="lg:col-span-9">
|
||||||
|
|
||||||
|
|
||||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
{/*{addClientIsOpen &&*/}
|
|
||||||
{/*<AddNewClientForm isOpen={addClientIsOpen} toggle={toggleAddClient}/>*/}
|
|
||||||
{/*}*/}
|
|
||||||
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
||||||
<div className="ml-4 mt-4">
|
<div className="ml-4 mt-4">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900">Actions</h3>
|
<h3 className="text-lg leading-6 font-medium text-gray-900">Actions</h3>
|
||||||
|
@ -18,7 +13,6 @@ function ActionSettings() {
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
className="relative inline-flex items-center px-4 py-2 border border-transparent shadow-sm text-sm font-medium rounded-md text-white bg-indigo-600 hover:bg-indigo-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"
|
||||||
// onClick={toggleAddClient}
|
|
||||||
>
|
>
|
||||||
Add new
|
Add new
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -39,7 +39,7 @@ function ApplicationSettings() {
|
||||||
id="host"
|
id="host"
|
||||||
value={data.host}
|
value={data.host}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -53,7 +53,7 @@ function ApplicationSettings() {
|
||||||
id="port"
|
id="port"
|
||||||
value={data.port}
|
value={data.port}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -67,7 +67,7 @@ function ApplicationSettings() {
|
||||||
id="base_url"
|
id="base_url"
|
||||||
value={data.base_url}
|
value={data.base_url}
|
||||||
disabled={true}
|
disabled={true}
|
||||||
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 border border-gray-300 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
className="mt-2 block w-full dark:bg-gray-800 border border-gray-300 dark:border-gray-700 rounded-md shadow-sm py-2 px-3 focus:outline-none focus:ring-blue-500 focus:border-blue-500 dark:text-gray-100 sm:text-sm"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -80,19 +80,21 @@ function ApplicationSettings() {
|
||||||
{data?.version ? (
|
{data?.version ? (
|
||||||
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
||||||
<dt className="font-medium text-gray-500 dark:text-white">Version:</dt>
|
<dt className="font-medium text-gray-500 dark:text-white">Version:</dt>
|
||||||
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2">{data?.version}</dd>
|
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2 break-all">
|
||||||
|
{data?.version}
|
||||||
|
</dd>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{data?.commit ? (
|
{data?.commit ? (
|
||||||
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
||||||
<dt className="font-medium text-gray-500 dark:text-white">Commit:</dt>
|
<dt className="font-medium text-gray-500 dark:text-white">Commit:</dt>
|
||||||
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2">{data.commit}</dd>
|
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2 break-all">{data.commit}</dd>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
{data?.date ? (
|
{data?.date ? (
|
||||||
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
<div className="py-4 sm:py-5 sm:grid sm:grid-cols-4 sm:gap-4 sm:px-6">
|
||||||
<dt className="font-medium text-gray-500 dark:text-white">Date:</dt>
|
<dt className="font-medium text-gray-500 dark:text-white">Date:</dt>
|
||||||
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2">{data?.date}</dd>
|
<dd className="mt-1 text-gray-900 dark:text-white sm:mt-0 sm:col-span-2 break-all">{data?.date}</dd>
|
||||||
</div>
|
</div>
|
||||||
) : null}
|
) : null}
|
||||||
</dl>
|
</dl>
|
||||||
|
@ -123,7 +125,6 @@ function ApplicationSettings() {
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -86,7 +86,7 @@ function DownloadClientSettings() {
|
||||||
return (<p>An error has occurred: </p>);
|
return (<p>An error has occurred: </p>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
<div className="lg:col-span-9">
|
||||||
|
|
||||||
<DownloadClientAddForm isOpen={addClientIsOpen} toggle={toggleAddClient} />
|
<DownloadClientAddForm isOpen={addClientIsOpen} toggle={toggleAddClient} />
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ function FeedSettings() {
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
<div className="lg:col-span-9">
|
||||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
||||||
<div className="ml-4 mt-4">
|
<div className="ml-4 mt-4">
|
||||||
|
|
|
@ -82,7 +82,7 @@ function IndexerSettings() {
|
||||||
return (<p>An error has occurred</p>);
|
return (<p>An error has occurred</p>);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
<div className="lg:col-span-9">
|
||||||
|
|
||||||
<IndexerAddForm isOpen={addIndexerIsOpen} toggle={toggleAddIndexer} />
|
<IndexerAddForm isOpen={addIndexerIsOpen} toggle={toggleAddIndexer} />
|
||||||
|
|
||||||
|
|
|
@ -1,41 +1,35 @@
|
||||||
import { useQuery } from "react-query";
|
import { useQuery } from "react-query";
|
||||||
|
|
||||||
import {
|
import { simplifyDate, IsEmptyDate, classNames } from "../../utils";
|
||||||
simplifyDate,
|
import { IrcNetworkAddForm, IrcNetworkUpdateForm } from "../../forms";
|
||||||
IsEmptyDate
|
|
||||||
} from "../../utils";
|
|
||||||
import {
|
|
||||||
IrcNetworkAddForm,
|
|
||||||
IrcNetworkUpdateForm
|
|
||||||
} from "../../forms";
|
|
||||||
import { useToggle } from "../../hooks/hooks";
|
import { useToggle } from "../../hooks/hooks";
|
||||||
import { APIClient } from "../../api/APIClient";
|
import { APIClient } from "../../api/APIClient";
|
||||||
import { EmptySimple } from "../../components/emptystates";
|
import { EmptySimple } from "../../components/emptystates";
|
||||||
import { ExclamationCircleIcon } from "@heroicons/react/outline";
|
import { ExclamationCircleIcon } from "@heroicons/react/outline";
|
||||||
|
import { LockClosedIcon, LockOpenIcon } from "@heroicons/react/solid";
|
||||||
|
|
||||||
export const IrcSettings = () => {
|
export const IrcSettings = () => {
|
||||||
const [addNetworkIsOpen, toggleAddNetwork] = useToggle(false);
|
const [addNetworkIsOpen, toggleAddNetwork] = useToggle(false);
|
||||||
|
|
||||||
const { data } = useQuery(
|
const { data } = useQuery("networks", () => APIClient.irc.getNetworks(), {
|
||||||
"networks",
|
|
||||||
() => APIClient.irc.getNetworks(),
|
|
||||||
{
|
|
||||||
refetchOnWindowFocus: false,
|
refetchOnWindowFocus: false,
|
||||||
// Refetch every 3 seconds
|
// Refetch every 3 seconds
|
||||||
refetchInterval: 3000
|
refetchInterval: 3000
|
||||||
}
|
});
|
||||||
);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="divide-y divide-gray-200 lg:col-span-9">
|
<div className="lg:col-span-9">
|
||||||
<IrcNetworkAddForm isOpen={addNetworkIsOpen} toggle={toggleAddNetwork} />
|
<IrcNetworkAddForm isOpen={addNetworkIsOpen} toggle={toggleAddNetwork} />
|
||||||
|
|
||||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
<div className="-ml-4 -mt-4 flex justify-between items-center flex-wrap sm:flex-nowrap">
|
||||||
<div className="ml-4 mt-4">
|
<div className="ml-4 mt-4">
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">IRC</h3>
|
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">
|
||||||
|
IRC
|
||||||
|
</h3>
|
||||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
IRC networks and channels. Click on a network to view channel status.
|
IRC networks and channels. Click on a network to view channel
|
||||||
|
status.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="ml-4 mt-4 flex-shrink-0">
|
<div className="ml-4 mt-4 flex-shrink-0">
|
||||||
|
@ -48,23 +42,34 @@ export const IrcSettings = () => {
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{data && data.length > 0 ? (
|
{data && data.length > 0 ? (
|
||||||
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
|
<section className="mt-6 light:bg-white dark:bg-gray-800 light:shadow sm:rounded-md">
|
||||||
<ol className="min-w-full">
|
<ol className="min-w-full">
|
||||||
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
{/* <div className="col-span-1 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Enabled</div> */}
|
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Network</div>
|
Network
|
||||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Server</div>
|
</div>
|
||||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Nick</div>
|
<div className="col-span-5 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
|
Server
|
||||||
|
</div>
|
||||||
|
<div className="col-span-3 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
|
Nick
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
{data &&
|
||||||
{data && data.map((network, idx) => (
|
data.map((network, idx) => (
|
||||||
<ListItem key={idx} idx={idx} network={network} />
|
<ListItem key={idx} idx={idx} network={network} />
|
||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
) : <EmptySimple title="No networks" subtitle="Add a new network" buttonText="New network" buttonAction={toggleAddNetwork} />}
|
) : (
|
||||||
|
<EmptySimple
|
||||||
|
title="No networks"
|
||||||
|
subtitle="Add a new network"
|
||||||
|
buttonText="New network"
|
||||||
|
buttonAction={toggleAddNetwork}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
@ -80,33 +85,91 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
||||||
const [edit, toggleEdit] = useToggle(false);
|
const [edit, toggleEdit] = useToggle(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|
||||||
<li key={idx}>
|
<li key={idx}>
|
||||||
<div className="grid grid-cols-12 gap-4 items-center hover:bg-gray-50 dark:hover:bg-gray-700 py-4">
|
<div className="grid grid-cols-12 gap-2 lg:gap-4 items-center hover:bg-gray-50 dark:hover:bg-gray-700 py-4">
|
||||||
<IrcNetworkUpdateForm isOpen={updateIsOpen} toggle={toggleUpdate} network={network} />
|
<IrcNetworkUpdateForm
|
||||||
|
isOpen={updateIsOpen}
|
||||||
|
toggle={toggleUpdate}
|
||||||
|
network={network}
|
||||||
|
/>
|
||||||
|
|
||||||
<div className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer" onClick={toggleEdit}>
|
<div
|
||||||
<span className="relative inline-flex items-center">
|
className="col-span-3 items-center sm:px-6 text-sm font-medium text-gray-900 dark:text-white cursor-pointer"
|
||||||
{
|
onClick={toggleEdit}
|
||||||
network.enabled ? (
|
>
|
||||||
networkHealthy(network) ? (
|
<div className="flex">
|
||||||
<span className="mr-3 flex h-3 w-3 relative" title={`Connected since: ${simplifyDate(network.connected_since)}`}>
|
<span className="relative inline-flex items-center ml-1">
|
||||||
|
{network.enabled ? (
|
||||||
|
IsNetworkHealthy(network) ? (
|
||||||
|
<span
|
||||||
|
className="mr-3 flex h-3 w-3 relative"
|
||||||
|
title={`Connected since: ${simplifyDate(network.connected_since)}`}
|
||||||
|
>
|
||||||
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
||||||
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
|
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
|
||||||
</span>
|
</span>
|
||||||
) : <span className="mr-3 flex items-center" title={network.connection_errors.toString()}><ExclamationCircleIcon className="h-4 w-4 text-red-400 hover:text-red-600" /></span>
|
) : (
|
||||||
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
|
<span
|
||||||
}
|
className="mr-3 flex items-center"
|
||||||
{network.name}
|
title={network.connection_errors.toString()}
|
||||||
|
>
|
||||||
|
<ExclamationCircleIcon className="h-4 w-4 text-red-400 hover:text-red-600" />
|
||||||
</span>
|
</span>
|
||||||
|
)
|
||||||
|
) : (
|
||||||
|
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<div className="overflow-x-auto flex">
|
||||||
|
{network.name}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div
|
||||||
|
className="col-span-5 sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||||
|
onClick={toggleEdit}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
className="overflow-x-auto flex items-center"
|
||||||
|
title={network.tls ? "Secured using TLS" : "Insecure, not using TLS"}
|
||||||
|
>
|
||||||
|
<div className="min-h-2 min-w-2">
|
||||||
|
{network.tls ? (
|
||||||
|
<LockClosedIcon
|
||||||
|
className={classNames(
|
||||||
|
"mr-2 h-4 w-4",
|
||||||
|
network.enabled ? "text-green-600" : "text-gray-500"
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
) : (
|
||||||
|
<LockOpenIcon className={classNames(
|
||||||
|
"mr-2 h-4 w-4",
|
||||||
|
network.enabled ? "text-red-500" : "text-yellow-500"
|
||||||
|
)} />
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
<p className="break-all">
|
||||||
|
{network.server}:{network.port}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="col-span-4 flex justify-between items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.server}:{network.port} {network.tls && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 dark:bg-green-300 text-green-800 dark:text-green-900">TLS</span>}</div>
|
|
||||||
{network.nickserv && network.nickserv.account ? (
|
{network.nickserv && network.nickserv.account ? (
|
||||||
<div className="col-span-4 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer" onClick={toggleEdit}>{network.nickserv.account}</div>
|
<div
|
||||||
) : <div className="col-span-4" />}
|
className="col-span-3 items-center sm:px-6 text-sm text-gray-500 dark:text-gray-400 cursor-pointer"
|
||||||
|
onClick={toggleEdit}
|
||||||
|
>
|
||||||
|
<div className="overflow-x-auto flex">
|
||||||
|
{network.nickserv.account}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
) : (
|
||||||
|
<div className="col-span-3" />
|
||||||
|
)}
|
||||||
<div className="col-span-1 text-sm text-gray-500 dark:text-gray-400">
|
<div className="col-span-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
<span className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdate}>
|
<span
|
||||||
|
className="text-indigo-600 dark:text-gray-300 hover:text-indigo-900 cursor-pointer"
|
||||||
|
onClick={toggleUpdate}
|
||||||
|
>
|
||||||
Edit
|
Edit
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
|
@ -117,39 +180,58 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
||||||
{network.channels.length > 0 ? (
|
{network.channels.length > 0 ? (
|
||||||
<ol>
|
<ol>
|
||||||
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
<li className="grid grid-cols-12 gap-4 border-b border-gray-200 dark:border-gray-700">
|
||||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Channel</div>
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Monitoring since</div>
|
Channel
|
||||||
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">Last announce</div>
|
</div>
|
||||||
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
|
Monitoring since
|
||||||
|
</div>
|
||||||
|
<div className="col-span-4 px-6 py-3 text-left text-xs font-medium text-gray-500 dark:text-gray-400 uppercase tracking-wider">
|
||||||
|
Last announce
|
||||||
|
</div>
|
||||||
</li>
|
</li>
|
||||||
{network.channels.map(c => (
|
{network.channels.map((c) => (
|
||||||
<li key={c.id} className="text-gray-500 dark:text-gray-400">
|
<li key={c.id} className="text-gray-500 dark:text-gray-400">
|
||||||
<div className="grid grid-cols-12 gap-4 items-center py-4">
|
<div className="grid grid-cols-12 gap-4 items-center py-4">
|
||||||
<div className="col-span-4 flex items-center sm:px-6 ">
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
<span className="relative inline-flex items-center">
|
<span className="relative inline-flex items-center">
|
||||||
{
|
{network.enabled ? (
|
||||||
network.enabled ? (
|
|
||||||
c.monitoring ? (
|
c.monitoring ? (
|
||||||
<span className="mr-3 flex h-3 w-3 relative" title="monitoring">
|
<span
|
||||||
|
className="mr-3 flex h-3 w-3 relative"
|
||||||
|
title="monitoring"
|
||||||
|
>
|
||||||
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
<span className="animate-ping inline-flex h-full w-full rounded-full bg-green-400 opacity-75" />
|
||||||
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
|
<span className="inline-flex absolute rounded-full h-3 w-3 bg-green-500" />
|
||||||
</span>
|
</span>
|
||||||
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />
|
) : (
|
||||||
) : <span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
|
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-red-400" />
|
||||||
}
|
)
|
||||||
|
) : (
|
||||||
|
<span className="mr-3 flex h-3 w-3 rounded-full opacity-75 bg-gray-500" />
|
||||||
|
)}
|
||||||
{c.name}
|
{c.name}
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-4 flex items-center sm:px-6 ">
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
<span className="" title={simplifyDate(c.monitoring_since)}>{IsEmptyDate(c.monitoring_since)}</span>
|
<span title={simplifyDate(c.monitoring_since)}>
|
||||||
|
{IsEmptyDate(c.monitoring_since)}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="col-span-4 flex items-center sm:px-6 ">
|
<div className="col-span-4 flex items-center sm:px-6 ">
|
||||||
<span className="" title={simplifyDate(c.last_announce)}>{IsEmptyDate(c.last_announce)}</span>
|
<span title={simplifyDate(c.last_announce)}>
|
||||||
|
{IsEmptyDate(c.last_announce)}
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ol>
|
</ol>
|
||||||
) : <div className="flex text-center justify-center py-4 dark:text-gray-500"><p>No channels!</p></div>}
|
) : (
|
||||||
|
<div className="flex text-center justify-center py-4 dark:text-gray-500">
|
||||||
|
<p>No channels!</p>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
|
@ -157,10 +239,5 @@ const ListItem = ({ idx, network }: ListItemProps) => {
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
function networkHealthy(network: IrcNetworkWithHealth): boolean {
|
const IsNetworkHealthy = (network: IrcNetworkWithHealth) =>
|
||||||
if (network.connection_errors.length > 0) {
|
network.connection_errors.length <= 0;
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
|
@ -2,7 +2,7 @@ import { useQuery } from "react-query";
|
||||||
import { APIClient } from "../../api/APIClient";
|
import { APIClient } from "../../api/APIClient";
|
||||||
import { EmptySimple } from "../../components/emptystates";
|
import { EmptySimple } from "../../components/emptystates";
|
||||||
import { useToggle } from "../../hooks/hooks";
|
import { useToggle } from "../../hooks/hooks";
|
||||||
import { NotificationAddForm, NotificationUpdateForm } from "../../forms/settings/NotifiactionForms";
|
import { NotificationAddForm, NotificationUpdateForm } from "../../forms/settings/NotificationForms";
|
||||||
import { Switch } from "@headlessui/react";
|
import { Switch } from "@headlessui/react";
|
||||||
import { classNames } from "../../utils";
|
import { classNames } from "../../utils";
|
||||||
import { componentMapType } from "../../forms/settings/DownloadClientForms";
|
import { componentMapType } from "../../forms/settings/DownloadClientForms";
|
||||||
|
|
|
@ -28,7 +28,11 @@ function ReleaseSettings() {
|
||||||
const cancelModalButtonRef = useRef(null);
|
const cancelModalButtonRef = useRef(null);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<form className="divide-y divide-gray-200 dark:divide-gray-700 lg:col-span-9" action="#" method="POST">
|
<form
|
||||||
|
className="lg:col-span-9"
|
||||||
|
action="#"
|
||||||
|
method="POST"
|
||||||
|
>
|
||||||
<DeleteModal
|
<DeleteModal
|
||||||
isOpen={deleteModalIsOpen}
|
isOpen={deleteModalIsOpen}
|
||||||
toggle={toggleDeleteModal}
|
toggle={toggleDeleteModal}
|
||||||
|
@ -40,7 +44,9 @@ function ReleaseSettings() {
|
||||||
|
|
||||||
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
<div className="py-6 px-4 sm:p-6 lg:pb-8">
|
||||||
<div>
|
<div>
|
||||||
<h2 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">Releases</h2>
|
<h2 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">
|
||||||
|
Releases
|
||||||
|
</h2>
|
||||||
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
<p className="mt-1 text-sm text-gray-500 dark:text-gray-400">
|
||||||
Release settings. Reset state.
|
Release settings. Reset state.
|
||||||
</p>
|
</p>
|
||||||
|
@ -50,25 +56,21 @@ function ReleaseSettings() {
|
||||||
<div className="pb-6 divide-y divide-gray-200 dark:divide-gray-700">
|
<div className="pb-6 divide-y divide-gray-200 dark:divide-gray-700">
|
||||||
<div className="px-4 py-5 sm:p-0">
|
<div className="px-4 py-5 sm:p-0">
|
||||||
<div className="px-4 py-5 sm:p-6">
|
<div className="px-4 py-5 sm:p-6">
|
||||||
|
|
||||||
<div>
|
<div>
|
||||||
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">Danger Zone</h3>
|
<h3 className="text-lg leading-6 font-medium text-gray-900 dark:text-white">
|
||||||
|
Danger Zone
|
||||||
|
</h3>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<ul className="p-4 mt-6 divide-y divide-gray-200 dark:divide-gray-700 border-red-500 border rounded-lg">
|
<div className="flex justify-between items-center p-4 mt-6 max-w-sm m-auto">
|
||||||
<div className="flex justify-between items-center py-2">
|
|
||||||
<p className="text-sm text-gray-500 dark:text-gray-400">
|
|
||||||
Delete all releases
|
|
||||||
</p>
|
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={toggleDeleteModal}
|
onClick={toggleDeleteModal}
|
||||||
className="inline-flex items-center justify-center px-4 py-2 border border-transparent font-medium rounded-md text-red-700 dark:text-red-100 bg-red-100 dark:bg-red-500 hover:bg-red-200 dark:hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:text-sm"
|
className="w-full inline-flex items-center justify-center px-4 py-2 border border-transparent font-medium rounded-md text-red-700 hover:text-red-900 dark:text-white bg-red-100 dark:bg-red-800 hover:bg-red-200 dark:hover:bg-red-700 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-red-500 sm:text-sm"
|
||||||
>
|
>
|
||||||
Delete all releases
|
Delete all releases
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</ul>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue