mirror of
https://github.com/idanoo/autobrr
synced 2025-07-23 08:49:13 +00:00
Refactor irc client (#19)
* refactor: update http handlers * feat: add trace log level * refactir: irc handler * refactor(definitions): add irc settings and invite cmd: * feat: add dft values to inputs * refactor: indexer irc forms * refactor(definitions): fix nickserv.password var: * feat: pre fill indexer name field * refactor: handle stopping and updates
This commit is contained in:
parent
5f69ae9380
commit
4d40d41628
48 changed files with 1380 additions and 943 deletions
|
@ -7,10 +7,11 @@ interface Props {
|
|||
name: string;
|
||||
label: string;
|
||||
description?: string;
|
||||
defaultValue?: boolean;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
const SwitchGroup: React.FC<Props> = ({name, label, description}) => (
|
||||
const SwitchGroup: React.FC<Props> = ({name, label, description, defaultValue}) => (
|
||||
<ul className="mt-2 divide-y divide-gray-200">
|
||||
<Switch.Group as="li" className="py-4 flex items-center justify-between">
|
||||
<div className="flex flex-col">
|
||||
|
@ -27,6 +28,7 @@ const SwitchGroup: React.FC<Props> = ({name, label, description}) => (
|
|||
|
||||
<Field
|
||||
name={name}
|
||||
defaultValue={defaultValue as any}
|
||||
render={({input: {onChange, checked, value}}) => (
|
||||
<Switch
|
||||
value={value}
|
||||
|
|
|
@ -1,18 +1,21 @@
|
|||
import {Field} from "react-final-form";
|
||||
import { Field } from "react-final-form";
|
||||
import React from "react";
|
||||
import Error from "./Error";
|
||||
import {classNames} from "../../styles/utils";
|
||||
import { classNames } from "../../styles/utils";
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
label?: string;
|
||||
help?: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: string;
|
||||
className?: string;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
const TextFieldWide: React.FC<Props> = ({name, label, placeholder, required, className}) => (
|
||||
<div
|
||||
const TextFieldWide: React.FC<Props> = ({ name, label, help, placeholder, defaultValue, required, hidden, className}) => (
|
||||
<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>
|
||||
|
||||
|
@ -23,17 +26,22 @@ const TextFieldWide: React.FC<Props> = ({name, label, placeholder, required, cla
|
|||
<div className="sm:col-span-2">
|
||||
<Field
|
||||
name={name}
|
||||
render={({input, meta}) => (
|
||||
defaultValue={defaultValue}
|
||||
render={({ input, meta }) => (
|
||||
<input
|
||||
{...input}
|
||||
id={name}
|
||||
type="text"
|
||||
className={classNames(meta.touched && meta.error ? "focus:ring-red-500 focus:border-red-500 border-red-500" : "focus:ring-indigo-500 focus:border-indigo-500 border-gray-300", "block w-full shadow-sm sm:text-sm rounded-md")}
|
||||
placeholder={placeholder}
|
||||
hidden={hidden}
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
<Error name={name} classNames="block text-red-500 mt-2"/>
|
||||
{help && (
|
||||
<p className="mt-2 text-sm text-gray-500" id="email-description">{help}</p>
|
||||
)}
|
||||
<Error name={name} classNames="block text-red-500 mt-2" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
|
|
|
@ -7,15 +7,19 @@ interface Props {
|
|||
name: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: number;
|
||||
className?: string;
|
||||
required?: boolean;
|
||||
hidden?: boolean;
|
||||
}
|
||||
|
||||
const NumberFieldWide: React.FC<Props> = ({
|
||||
name,
|
||||
label,
|
||||
placeholder,
|
||||
defaultValue,
|
||||
required,
|
||||
hidden,
|
||||
className,
|
||||
}) => (
|
||||
<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">
|
||||
|
@ -30,6 +34,7 @@ const NumberFieldWide: React.FC<Props> = ({
|
|||
<div className="sm:col-span-2">
|
||||
<Field
|
||||
name={name}
|
||||
defaultValue={defaultValue}
|
||||
parse={(v) => v & parseInt(v, 10)}
|
||||
render={({ input, meta }) => (
|
||||
<input
|
||||
|
|
56
web/src/components/inputs/wide/PasswordField.tsx
Normal file
56
web/src/components/inputs/wide/PasswordField.tsx
Normal file
|
@ -0,0 +1,56 @@
|
|||
import { Field } from "react-final-form";
|
||||
import Error from "../Error";
|
||||
import { classNames } from "../../../styles/utils";
|
||||
import { useToggle } from "../../../hooks/hooks";
|
||||
import { EyeIcon, EyeOffIcon } from "@heroicons/react/solid";
|
||||
|
||||
interface Props {
|
||||
name: string;
|
||||
label?: string;
|
||||
placeholder?: string;
|
||||
defaultValue?: string;
|
||||
help?: string;
|
||||
required?: boolean;
|
||||
}
|
||||
|
||||
function PasswordField({ name, label, placeholder, defaultValue, help, required }: Props) {
|
||||
const [isVisible, toggleVisibility] = useToggle(false)
|
||||
|
||||
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>
|
||||
|
||||
<label htmlFor={name} className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2">
|
||||
{label} {required && <span className="text-gray-500">*</span>}
|
||||
</label>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<Field
|
||||
name={name}
|
||||
defaultValue={defaultValue}
|
||||
render={({ input, meta }) => (
|
||||
<div className="relative">
|
||||
<input
|
||||
{...input}
|
||||
id={name}
|
||||
type={isVisible ? "text" : "password"}
|
||||
className={classNames(meta.touched && meta.error ? "focus:ring-red-500 focus:border-red-500 border-red-500" : "focus:ring-indigo-500 focus:border-indigo-500 border-gray-300", "block w-full shadow-sm sm:text-sm rounded-md")}
|
||||
placeholder={placeholder}
|
||||
/>
|
||||
<div className="absolute inset-y-0 right-0 px-3 flex items-center" onClick={toggleVisibility}>
|
||||
{!isVisible ? <EyeIcon className="h-5 w-5 text-gray-400 hover:text-gray-500" aria-hidden="true" /> : <EyeOffIcon className="h-5 w-5 text-gray-400 hover:text-gray-500" aria-hidden="true" />}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
/>
|
||||
{help && (
|
||||
<p className="mt-2 text-sm text-gray-500" id="email-description">{help}</p>
|
||||
)}
|
||||
<Error name={name} classNames="block text-red-500 mt-2" />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default PasswordField;
|
|
@ -1,3 +1,4 @@
|
|||
export { default as NumberFieldWide } from "./NumberField";
|
||||
export { default as PasswordFieldWide } from "./PasswordField";
|
||||
export { default as RadioFieldsetWide } from "./RadioFieldsetWide";
|
||||
export { default as SelectFieldWide } from "./SelectField";
|
||||
|
|
|
@ -31,6 +31,43 @@ export interface Indexer {
|
|||
settings: object | any;
|
||||
}
|
||||
|
||||
export interface IndexerSchema {
|
||||
// id: number;
|
||||
name: string;
|
||||
identifier: string;
|
||||
description: string;
|
||||
language: string;
|
||||
privacy: string;
|
||||
protocol: string;
|
||||
urls: string[];
|
||||
settings: IndexerSchemaSettings[];
|
||||
irc: IndexerSchemaIRC;
|
||||
}
|
||||
|
||||
|
||||
export interface IndexerSchemaSettings {
|
||||
name: string;
|
||||
type: string;
|
||||
required: boolean;
|
||||
label: string;
|
||||
help: string;
|
||||
description: string;
|
||||
default: string;
|
||||
}
|
||||
|
||||
export interface IndexerSchemaIRC {
|
||||
network: string;
|
||||
server: string;
|
||||
port: number;
|
||||
tls: boolean;
|
||||
nickserv: boolean;
|
||||
announcers: string[];
|
||||
channels: string[];
|
||||
invite: string[];
|
||||
invite_command: string;
|
||||
settings: IndexerSchemaSettings[];
|
||||
}
|
||||
|
||||
export interface Filter {
|
||||
id: number;
|
||||
name: string;
|
||||
|
@ -87,16 +124,29 @@ export interface DownloadClient {
|
|||
settings: object;
|
||||
}
|
||||
|
||||
export interface NickServ {
|
||||
account: string;
|
||||
password: string;
|
||||
}
|
||||
|
||||
export interface Network {
|
||||
id: number;
|
||||
id?: number;
|
||||
name: string;
|
||||
enabled: boolean;
|
||||
addr: string;
|
||||
nick: string;
|
||||
username: string;
|
||||
realname: string;
|
||||
pass: string;
|
||||
sasl: SASL;
|
||||
server: string;
|
||||
port: number;
|
||||
tls: boolean;
|
||||
invite_command: string;
|
||||
nickserv: {
|
||||
account: string;
|
||||
password: string;
|
||||
}
|
||||
channels: Channel[];
|
||||
settings: object;
|
||||
}
|
||||
|
||||
export interface Channel {
|
||||
name: string;
|
||||
}
|
||||
|
||||
export interface SASL {
|
||||
|
|
|
@ -1,23 +1,24 @@
|
|||
import React, {Fragment} from "react";
|
||||
import {useMutation, useQuery} from "react-query";
|
||||
import {Indexer} from "../../domain/interfaces";
|
||||
import {sleep} from "../../utils/utils";
|
||||
import {XIcon} from "@heroicons/react/solid";
|
||||
import {Dialog, Transition} from "@headlessui/react";
|
||||
import {Field, Form} from "react-final-form";
|
||||
import React, { Fragment } from "react";
|
||||
import { useMutation, useQuery } from "react-query";
|
||||
import { Channel, Indexer, IndexerSchema, IndexerSchemaSettings, Network } from "../../domain/interfaces";
|
||||
import { sleep } from "../../utils/utils";
|
||||
import { XIcon } from "@heroicons/react/solid";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
import DEBUG from "../../components/debug";
|
||||
import Select from "react-select";
|
||||
import {queryClient} from "../../App";
|
||||
import { SwitchGroup } from "../../components/inputs";
|
||||
import { queryClient } from "../../App";
|
||||
import { SwitchGroup, TextFieldWide } from "../../components/inputs";
|
||||
import APIClient from "../../api/APIClient";
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
interface props {
|
||||
isOpen: boolean;
|
||||
toggle: any;
|
||||
}
|
||||
|
||||
function IndexerAddForm({isOpen, toggle}: props) {
|
||||
const {data} = useQuery<any[], Error>('indexerSchema', APIClient.indexers.getSchema,
|
||||
function IndexerAddForm({ isOpen, toggle }: props) {
|
||||
const { data } = useQuery<IndexerSchema[], Error>('indexerSchema', APIClient.indexers.getSchema,
|
||||
{
|
||||
enabled: isOpen,
|
||||
refetchOnWindowFocus: false
|
||||
|
@ -33,59 +34,122 @@ function IndexerAddForm({isOpen, toggle}: props) {
|
|||
}
|
||||
})
|
||||
|
||||
const onSubmit = (data: any) => {
|
||||
mutation.mutate(data)
|
||||
const ircMutation = useMutation((network: Network) => APIClient.irc.createNetwork(network), {
|
||||
onSuccess: (data) => {
|
||||
console.log("irc mutation: ", data);
|
||||
|
||||
// queryClient.invalidateQueries(['indexer']);
|
||||
// sleep(1500)
|
||||
|
||||
// toggle()
|
||||
}
|
||||
})
|
||||
|
||||
const onSubmit = (formData: any) => {
|
||||
let ind = data && data.find(i => i.identifier === formData.identifier)
|
||||
|
||||
if (!ind) {
|
||||
return
|
||||
}
|
||||
|
||||
let channels: Channel[] = []
|
||||
if (ind.irc.channels.length) {
|
||||
ind.irc.channels.forEach(element => {
|
||||
channels.push({ name: element })
|
||||
});
|
||||
}
|
||||
|
||||
const network: Network = {
|
||||
name: ind.name,
|
||||
enabled: false,
|
||||
server: formData.irc.server,
|
||||
port: formData.irc.port,
|
||||
tls: formData.irc.tls,
|
||||
nickserv: formData.irc.nickserv,
|
||||
invite_command: formData.irc.invite_command,
|
||||
settings: formData.irc.settings,
|
||||
channels: channels,
|
||||
}
|
||||
|
||||
console.log("network: ", network);
|
||||
|
||||
|
||||
mutation.mutate(formData, {
|
||||
onSuccess: (data) => {
|
||||
// create irc
|
||||
ircMutation.mutate(network)
|
||||
}
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
const renderSettingFields = (indexer: string) => {
|
||||
if (indexer !== "") {
|
||||
// let ind = data.find(i => i.implementation_name === indexer)
|
||||
let ind = data && data.find(i => i.identifier === indexer)
|
||||
|
||||
return (
|
||||
<div key="opt">
|
||||
{ind && ind.settings && ind.settings.map((f: any, idx: number) => {
|
||||
switch (f.type) {
|
||||
case "text":
|
||||
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" key={idx}>
|
||||
<div>
|
||||
<label
|
||||
htmlFor={f.name}
|
||||
className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2"
|
||||
>
|
||||
{f.label}
|
||||
</label>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<Field name={"settings."+f.name}>
|
||||
{({input, meta}) => (
|
||||
<div className="sm:col-span-2">
|
||||
<input
|
||||
type="text"
|
||||
{...input}
|
||||
className="block w-full shadow-sm sm:text-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
|
||||
/>
|
||||
{meta.touched && meta.error &&
|
||||
<span>{meta.error}</span>}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
})}
|
||||
{ind && ind.settings && ind.settings.map((f: any, idx: number) => {
|
||||
switch (f.type) {
|
||||
case "text":
|
||||
return (
|
||||
<TextFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} defaultValue=""/>
|
||||
)
|
||||
case "secret":
|
||||
return (
|
||||
<PasswordFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} defaultValue="" />
|
||||
)
|
||||
}
|
||||
})}
|
||||
<div hidden={true}>
|
||||
<TextFieldWide name={`name`} label="Name" defaultValue={ind?.name} />
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
const renderIrcSettingFields = (indexer: string) => {
|
||||
|
||||
if (indexer !== "") {
|
||||
let ind = data && data.find(i => i.identifier === indexer)
|
||||
|
||||
return (
|
||||
<Fragment>
|
||||
{ind && ind.irc && ind.irc.settings && (
|
||||
<div className="border-t border-gray-200 py-5">
|
||||
<div className="px-6 space-y-1">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900">IRC</Dialog.Title>
|
||||
<p className="text-sm text-gray-500">
|
||||
Networks, channels and invite commands are configured automatically.
|
||||
</p>
|
||||
</div>
|
||||
{ind.irc.settings.map((f: IndexerSchemaSettings, idx: number) => {
|
||||
switch (f.type) {
|
||||
case "text":
|
||||
return <TextFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} />
|
||||
case "secret":
|
||||
return <PasswordFieldWide name={`irc.${f.name}`} label={f.label} required={f.required} key={idx} help={f.help} defaultValue={f.default} />
|
||||
}
|
||||
})}
|
||||
|
||||
<div hidden={true}>
|
||||
<TextFieldWide name={`irc.server`} label="Server" defaultValue={ind.irc.server} />
|
||||
<NumberFieldWide name={`irc.port`} label="Port" defaultValue={ind.irc.port} />
|
||||
<SwitchGroup name="irc.tls" label="TLS" defaultValue={ind.irc.tls} />
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</Fragment>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden" open={isOpen} onClose={toggle}>
|
||||
<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">
|
||||
<Transition.Child
|
||||
|
@ -100,18 +164,17 @@ function IndexerAddForm({isOpen, toggle}: props) {
|
|||
<div className="w-screen max-w-2xl">
|
||||
<Form
|
||||
initialValues={{
|
||||
name: "",
|
||||
enabled: true,
|
||||
identifier: "",
|
||||
irc: {}
|
||||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({handleSubmit, values}) => {
|
||||
{({ handleSubmit, values }) => {
|
||||
return (
|
||||
<form className="h-full flex flex-col bg-white shadow-xl overflow-y-scroll"
|
||||
onSubmit={handleSubmit}>
|
||||
onSubmit={handleSubmit}>
|
||||
<div className="flex-1">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-6 bg-gray-50 sm:px-6">
|
||||
<div className="flex items-start justify-between space-x-3">
|
||||
<div className="space-y-1">
|
||||
|
@ -129,43 +192,14 @@ function IndexerAddForm({isOpen, toggle}: props) {
|
|||
onClick={toggle}
|
||||
>
|
||||
<span className="sr-only">Close panel</span>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true"/>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Divider container */}
|
||||
<div
|
||||
className="py-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>
|
||||
<label
|
||||
htmlFor="name"
|
||||
className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2"
|
||||
>
|
||||
Name
|
||||
</label>
|
||||
</div>
|
||||
<Field name="name">
|
||||
{({input, meta}) => (
|
||||
<div className="sm:col-span-2">
|
||||
<input
|
||||
type="text"
|
||||
{...input}
|
||||
className="block w-full shadow-sm sm:text-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
|
||||
/>
|
||||
{meta.touched && meta.error &&
|
||||
<span>{meta.error}</span>}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
|
||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<SwitchGroup name="enabled" label="Enabled" />
|
||||
</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">
|
||||
|
@ -182,26 +216,32 @@ function IndexerAddForm({isOpen, toggle}: props) {
|
|||
name="identifier"
|
||||
parse={val => val && val.value}
|
||||
format={val => data && data.find((o: any) => o.value === val)}
|
||||
render={({input, meta}) => (
|
||||
render={({ input, meta }) => (
|
||||
<React.Fragment>
|
||||
<Select {...input}
|
||||
isClearable={true}
|
||||
placeholder="Choose an indexer"
|
||||
options={data && data.sort((a,b): any => a.name.localeCompare(b.name)).map(v => ({
|
||||
label: v.name,
|
||||
value: v.identifier
|
||||
// value: v.implementation_name
|
||||
}))}/>
|
||||
{/*<Error name={input.name} classNames="text-red mt-2 block" />*/}
|
||||
isClearable={true}
|
||||
placeholder="Choose an indexer"
|
||||
|
||||
options={data && data.sort((a, b): any => a.name.localeCompare(b.name)).map(v => ({
|
||||
label: v.name,
|
||||
value: v.identifier
|
||||
}))} />
|
||||
</React.Fragment>
|
||||
)}
|
||||
/>
|
||||
</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">
|
||||
<SwitchGroup name="enabled" label="Enabled" />
|
||||
</div>
|
||||
|
||||
|
||||
{renderSettingFields(values.identifier)}
|
||||
|
||||
</div>
|
||||
|
||||
{renderIrcSettingFields(values.identifier)}
|
||||
</div>
|
||||
|
||||
<div
|
||||
|
@ -223,7 +263,7 @@ function IndexerAddForm({isOpen, toggle}: props) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<DEBUG values={values}/>
|
||||
<DEBUG values={values} />
|
||||
</form>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
import {Fragment, useRef} from "react";
|
||||
import {useMutation } from "react-query";
|
||||
import {Indexer} from "../../domain/interfaces";
|
||||
import {sleep} from "../../utils/utils";
|
||||
import {ExclamationIcon, XIcon} from "@heroicons/react/solid";
|
||||
import {Dialog, Transition} from "@headlessui/react";
|
||||
import {Field, Form} from "react-final-form";
|
||||
import { Fragment, useRef } from "react";
|
||||
import { useMutation } from "react-query";
|
||||
import { Indexer } from "../../domain/interfaces";
|
||||
import { sleep } from "../../utils/utils";
|
||||
import { ExclamationIcon, XIcon } from "@heroicons/react/solid";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { Field, Form } from "react-final-form";
|
||||
import DEBUG from "../../components/debug";
|
||||
import { SwitchGroup } from "../../components/inputs";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import { SwitchGroup, TextFieldWide } from "../../components/inputs";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import APIClient from "../../api/APIClient";
|
||||
import {queryClient} from "../../App";
|
||||
import { queryClient } from "../../App";
|
||||
import { PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
interface props {
|
||||
isOpen: boolean;
|
||||
|
@ -17,7 +18,7 @@ interface props {
|
|||
indexer: Indexer;
|
||||
}
|
||||
|
||||
function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
||||
function IndexerUpdateForm({ isOpen, toggle, indexer }: props) {
|
||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false)
|
||||
|
||||
const mutation = useMutation((indexer: Indexer) => APIClient.indexers.update(indexer), {
|
||||
|
@ -55,31 +56,11 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
switch (f.type) {
|
||||
case "text":
|
||||
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" key={idx}>
|
||||
<div>
|
||||
<label
|
||||
htmlFor={f.name}
|
||||
className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2"
|
||||
>
|
||||
{f.label}
|
||||
</label>
|
||||
</div>
|
||||
<div className="sm:col-span-2">
|
||||
<Field name={"settings."+f.name}>
|
||||
{({input, meta}) => (
|
||||
<div className="sm:col-span-2">
|
||||
<input
|
||||
type="text"
|
||||
{...input}
|
||||
className="block w-full shadow-sm sm:text-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
|
||||
/>
|
||||
{meta.touched && meta.error &&
|
||||
<span>{meta.error}</span>}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
</div>
|
||||
</div>
|
||||
<TextFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} />
|
||||
)
|
||||
case "secret":
|
||||
return (
|
||||
<PasswordFieldWide name={`settings.${f.name}`} label={f.label} key={idx} help={f.help} />
|
||||
)
|
||||
}
|
||||
})}
|
||||
|
@ -88,9 +69,6 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
}
|
||||
}
|
||||
|
||||
// const setss = indexer.settings.reduce((o: any, obj: any) => ({ ...o, [obj.name]: obj.value }), {})
|
||||
// console.log("setts", setss)
|
||||
|
||||
return (
|
||||
<Transition.Root show={isOpen} as={Fragment}>
|
||||
<Dialog as="div" static className="fixed inset-0 overflow-hidden" open={isOpen} onClose={toggle}>
|
||||
|
@ -119,8 +97,8 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
|
||||
{/* This element is to trick the browser into centering the modal contents. */}
|
||||
<span className="hidden sm:inline-block sm:align-middle sm:h-screen" aria-hidden="true">
|
||||
​
|
||||
</span>
|
||||
​
|
||||
</span>
|
||||
<Transition.Child
|
||||
as={Fragment}
|
||||
enter="ease-out duration-300"
|
||||
|
@ -172,7 +150,7 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
</Dialog>
|
||||
</Transition.Root>
|
||||
<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">
|
||||
<Transition.Child
|
||||
|
@ -195,12 +173,11 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
}}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({handleSubmit, values}) => {
|
||||
{({ handleSubmit, values }) => {
|
||||
return (
|
||||
<form className="h-full flex flex-col bg-white shadow-xl overflow-y-scroll"
|
||||
onSubmit={handleSubmit}>
|
||||
onSubmit={handleSubmit}>
|
||||
<div className="flex-1">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-6 bg-gray-50 sm:px-6">
|
||||
<div className="flex items-start justify-between space-x-3">
|
||||
<div className="space-y-1">
|
||||
|
@ -218,13 +195,12 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
onClick={toggle}
|
||||
>
|
||||
<span className="sr-only">Close panel</span>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true"/>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{/* Divider container */}
|
||||
<div
|
||||
className="py-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<div
|
||||
|
@ -238,7 +214,7 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
</label>
|
||||
</div>
|
||||
<Field name="name">
|
||||
{({input, meta}) => (
|
||||
{({ input, meta }) => (
|
||||
<div className="sm:col-span-2">
|
||||
<input
|
||||
type="text"
|
||||
|
@ -246,7 +222,7 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
className="block w-full shadow-sm sm:text-sm focus:ring-indigo-500 focus:border-indigo-500 border-gray-300 rounded-md"
|
||||
/>
|
||||
{meta.touched && meta.error &&
|
||||
<span>{meta.error}</span>}
|
||||
<span>{meta.error}</span>}
|
||||
</div>
|
||||
)}
|
||||
</Field>
|
||||
|
@ -289,7 +265,7 @@ function IndexerUpdateForm({isOpen, toggle, indexer}: props) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<DEBUG values={values}/>
|
||||
<DEBUG values={values} />
|
||||
</form>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -5,26 +5,14 @@ import {Dialog, Transition} from "@headlessui/react";
|
|||
import {XIcon} from "@heroicons/react/solid";
|
||||
import {Field, Form} from "react-final-form";
|
||||
import DEBUG from "../../components/debug";
|
||||
import {SwitchGroup, TextAreaWide, TextFieldWide} from "../../components/inputs";
|
||||
import {SwitchGroup, TextFieldWide} from "../../components/inputs";
|
||||
import {queryClient} from "../../App";
|
||||
|
||||
import arrayMutators from "final-form-arrays";
|
||||
import { FieldArray } from "react-final-form-arrays";
|
||||
import {classNames} from "../../styles/utils";
|
||||
import APIClient from "../../api/APIClient";
|
||||
|
||||
|
||||
// interface radioFieldsetOption {
|
||||
// label: string;
|
||||
// description: string;
|
||||
// value: string;
|
||||
// }
|
||||
|
||||
// const saslTypeOptions: radioFieldsetOption[] = [
|
||||
// {label: "None", description: "None", value: ""},
|
||||
// {label: "Plain", description: "SASL plain", value: "PLAIN"},
|
||||
// {label: "NickServ", description: "/NS identify", value: "NICKSERV"},
|
||||
// ];
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
function IrcNetworkAddForm({isOpen, toggle}: any) {
|
||||
const mutation = useMutation((network: Network) => APIClient.irc.createNetwork(network), {
|
||||
|
@ -53,12 +41,8 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
errors.name = "Required";
|
||||
}
|
||||
|
||||
if (!values.addr) {
|
||||
errors.addr = "Required";
|
||||
}
|
||||
|
||||
if (!values.nick) {
|
||||
errors.nick = "Required";
|
||||
if (!values.server) {
|
||||
errors.server = "Required";
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
@ -86,18 +70,9 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
initialValues={{
|
||||
name: "",
|
||||
enabled: true,
|
||||
addr: "",
|
||||
server: "",
|
||||
tls: false,
|
||||
nick: "",
|
||||
pass: "",
|
||||
// connect_commands: "",
|
||||
// sasl: {
|
||||
// mechanism: "",
|
||||
// plain: {
|
||||
// username: "",
|
||||
// password: "",
|
||||
// }
|
||||
// },
|
||||
}}
|
||||
mutators={{
|
||||
...arrayMutators
|
||||
|
@ -110,7 +85,6 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
<form className="h-full flex flex-col bg-white shadow-xl overflow-y-scroll"
|
||||
onSubmit={handleSubmit}>
|
||||
<div className="flex-1">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-6 bg-gray-50 sm:px-6">
|
||||
<div className="flex items-start justify-between space-x-3">
|
||||
<div className="space-y-1">
|
||||
|
@ -144,88 +118,19 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<TextFieldWide name="addr" label="Address" placeholder="Address:port eg irc.server.net:6697" required={true} />
|
||||
<TextFieldWide name="server" label="Server" placeholder="Address: Eg irc.server.net" required={true} />
|
||||
<NumberFieldWide name="port" label="Port" 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">
|
||||
<SwitchGroup name="tls" label="TLS"/>
|
||||
</div>
|
||||
|
||||
<TextFieldWide name="nick" label="Nick" placeholder="Nick" required={true} />
|
||||
<PasswordFieldWide name="pass" label="Password" help="Network password" />
|
||||
|
||||
<TextFieldWide name="password" label="Password" placeholder="Network password" />
|
||||
<TextFieldWide name="nickserv.account" label="NickServ Account" required={true} />
|
||||
<PasswordFieldWide name="nickserv.password" label="NickServ Password" />
|
||||
|
||||
<TextAreaWide name="connect_commands" label="Connect commands" placeholder="/msg test this" />
|
||||
|
||||
|
||||
{/* <Field*/}
|
||||
{/* name="sasl.mechanism"*/}
|
||||
{/* type="select"*/}
|
||||
{/* render={({input}) => (*/}
|
||||
{/* <Listbox value={input.value} onChange={input.onChange}>*/}
|
||||
{/* {({open}) => (*/}
|
||||
{/* <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>*/}
|
||||
{/* <Listbox.Label className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2">SASL / auth</Listbox.Label>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="sm:col-span-2 relative">*/}
|
||||
{/* <Listbox.Button*/}
|
||||
{/* className="bg-white relative w-full border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">*/}
|
||||
{/* <span className="block truncate">{input.value ? saslTypeOptions.find(c => c.value === input.value)!.label : "Choose auth method"}</span>*/}
|
||||
{/* <span className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">*/}
|
||||
{/* <SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>*/}
|
||||
{/*</span>*/}
|
||||
{/* </Listbox.Button>*/}
|
||||
|
||||
{/* <Transition*/}
|
||||
{/* show={open}*/}
|
||||
{/* as={Fragment}*/}
|
||||
{/* leave="transition ease-in duration-100"*/}
|
||||
{/* leaveFrom="opacity-100"*/}
|
||||
{/* leaveTo="opacity-0"*/}
|
||||
{/* >*/}
|
||||
{/* <Listbox.Options*/}
|
||||
{/* static*/}
|
||||
{/* className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"*/}
|
||||
{/* >*/}
|
||||
{/* {saslTypeOptions.map((opt: any) => (*/}
|
||||
{/* <Listbox.Option*/}
|
||||
{/* key={opt.value}*/}
|
||||
{/* className={({active}) =>*/}
|
||||
{/* classNames(*/}
|
||||
{/* active ? 'text-white bg-indigo-600' : 'text-gray-900',*/}
|
||||
{/* 'cursor-default select-none relative py-2 pl-3 pr-9'*/}
|
||||
{/* )*/}
|
||||
{/* }*/}
|
||||
{/* value={opt.value}*/}
|
||||
{/* >*/}
|
||||
{/* {({selected, active}) => (*/}
|
||||
{/* <>*/}
|
||||
{/* <span className={classNames(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>*/}
|
||||
{/* {opt.label}*/}
|
||||
{/* </span>*/}
|
||||
|
||||
{/* {selected ? (*/}
|
||||
{/* <span*/}
|
||||
{/* className={classNames(*/}
|
||||
{/* active ? 'text-white' : 'text-indigo-600',*/}
|
||||
{/* 'absolute inset-y-0 right-0 flex items-center pr-4'*/}
|
||||
{/* )}*/}
|
||||
{/* >*/}
|
||||
{/* <CheckIcon className="h-5 w-5" aria-hidden="true"/>*/}
|
||||
{/* </span>*/}
|
||||
{/* ) : null}*/}
|
||||
{/* </>*/}
|
||||
{/* )}*/}
|
||||
{/* </Listbox.Option>*/}
|
||||
{/* ))}*/}
|
||||
{/* </Listbox.Options>*/}
|
||||
{/* </Transition>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* )}*/}
|
||||
{/* </Listbox>*/}
|
||||
{/* )} />*/}
|
||||
<PasswordFieldWide name="invite_command" label="Invite command" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -295,7 +200,6 @@ function IrcNetworkAddForm({isOpen, toggle}: any) {
|
|||
<button
|
||||
type="submit"
|
||||
disabled={pristine || invalid}
|
||||
// className="inline-flex justify-center py-2 px-4 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={classNames(pristine || invalid ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700","inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500")}
|
||||
>
|
||||
Create
|
||||
|
|
|
@ -1,34 +1,22 @@
|
|||
import {Fragment, useEffect, useRef} from "react";
|
||||
import {useMutation} from "react-query";
|
||||
import {Network} from "../../domain/interfaces";
|
||||
import {Dialog, Transition} from "@headlessui/react";
|
||||
import {XIcon} from "@heroicons/react/solid";
|
||||
import {Field, Form} from "react-final-form";
|
||||
import { Fragment, useEffect, useRef } from "react";
|
||||
import { useMutation } from "react-query";
|
||||
import { Network } from "../../domain/interfaces";
|
||||
import { Dialog, Transition } from "@headlessui/react";
|
||||
import { XIcon } from "@heroicons/react/solid";
|
||||
import { Field, Form } from "react-final-form";
|
||||
import DEBUG from "../../components/debug";
|
||||
import {SwitchGroup, TextAreaWide, TextFieldWide} from "../../components/inputs";
|
||||
import {queryClient} from "../../App";
|
||||
import { SwitchGroup, TextFieldWide } from "../../components/inputs";
|
||||
import { queryClient } from "../../App";
|
||||
|
||||
import arrayMutators from "final-form-arrays";
|
||||
import { FieldArray } from "react-final-form-arrays";
|
||||
import {classNames} from "../../styles/utils";
|
||||
import {useToggle} from "../../hooks/hooks";
|
||||
import {DeleteModal} from "../../components/modals";
|
||||
import { classNames } from "../../styles/utils";
|
||||
import { useToggle } from "../../hooks/hooks";
|
||||
import { DeleteModal } from "../../components/modals";
|
||||
import APIClient from "../../api/APIClient";
|
||||
import { NumberFieldWide, PasswordFieldWide } from "../../components/inputs/wide";
|
||||
|
||||
|
||||
// interface radioFieldsetOption {
|
||||
// label: string;
|
||||
// description: string;
|
||||
// value: string;
|
||||
// }
|
||||
//
|
||||
// const saslTypeOptions: radioFieldsetOption[] = [
|
||||
// {label: "None", description: "None", value: ""},
|
||||
// {label: "Plain", description: "SASL plain", value: "PLAIN"},
|
||||
// {label: "NickServ", description: "/NS identify", value: "NICKSERV"},
|
||||
// ];
|
||||
|
||||
function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
||||
function IrcNetworkUpdateForm({ isOpen, toggle, network }: any) {
|
||||
const [deleteModalIsOpen, toggleDeleteModal] = useToggle(false)
|
||||
|
||||
const mutation = useMutation((network: Network) => APIClient.irc.updateNetwork(network), {
|
||||
|
@ -59,7 +47,7 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
// let cmds = data.connect_commands && data.connect_commands.length > 0 ? data.connect_commands.replace(/\r\n/g,"\n").split("\n") : [];
|
||||
// data.connect_commands = cmds
|
||||
// console.log("formatted", data)
|
||||
|
||||
|
||||
mutation.mutate(data)
|
||||
};
|
||||
|
||||
|
@ -70,12 +58,16 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
errors.name = "Required";
|
||||
}
|
||||
|
||||
if (!values.addr) {
|
||||
errors.addr = "Required";
|
||||
if (!values.server) {
|
||||
errors.server = "Required";
|
||||
}
|
||||
|
||||
if (!values.nick) {
|
||||
errors.nick = "Required";
|
||||
if (!values.port) {
|
||||
errors.port = "Required";
|
||||
}
|
||||
|
||||
if (!values.nickserv.account) {
|
||||
errors.nickserv.account = "Required";
|
||||
}
|
||||
|
||||
return errors;
|
||||
|
@ -98,7 +90,7 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
text="Are you sure you want to remove this network and channels? This action cannot be undone."
|
||||
/>
|
||||
<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">
|
||||
<Transition.Child
|
||||
|
@ -117,19 +109,13 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
id: network.id,
|
||||
name: network.name,
|
||||
enabled: network.enabled,
|
||||
addr: network.addr,
|
||||
server: network.server,
|
||||
port: network.port,
|
||||
tls: network.tls,
|
||||
nick: network.nick,
|
||||
nickserv: network.nickserv,
|
||||
pass: network.pass,
|
||||
invite_command: network.invite_command,
|
||||
connect_commands: network.connect_commands,
|
||||
sasl: network.sasl,
|
||||
// sasl: {
|
||||
// mechanism: network.sasl.mechanism,
|
||||
// plain: {
|
||||
// username: network.sasl.plain.username,
|
||||
// password: network.sasl.plain.password,
|
||||
// }
|
||||
// },
|
||||
channels: network.channels
|
||||
}}
|
||||
mutators={{
|
||||
|
@ -138,10 +124,10 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
validate={validate}
|
||||
onSubmit={onSubmit}
|
||||
>
|
||||
{({handleSubmit, values, pristine, invalid}) => {
|
||||
{({ handleSubmit, values, pristine, invalid }) => {
|
||||
return (
|
||||
<form className="h-full flex flex-col bg-white shadow-xl overflow-y-scroll"
|
||||
onSubmit={handleSubmit}>
|
||||
onSubmit={handleSubmit}>
|
||||
<div className="flex-1">
|
||||
{/* Header */}
|
||||
<div className="px-4 py-6 bg-gray-50 sm:px-6">
|
||||
|
@ -160,106 +146,48 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
onClick={toggle}
|
||||
>
|
||||
<span className="sr-only">Close panel</span>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true"/>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<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 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">
|
||||
<SwitchGroup name="enabled" label="Enabled"/>
|
||||
<SwitchGroup name="enabled" label="Enabled" />
|
||||
</div>
|
||||
|
||||
<div>
|
||||
|
||||
<TextFieldWide name="addr" label="Address" placeholder="Address:port eg irc.server.net:6697" required={true} />
|
||||
<div className="px-6 space-y-1 mt-6">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900">Connection</Dialog.Title>
|
||||
{/* <p className="text-sm text-gray-500">
|
||||
Networks, channels and invite commands are configured automatically.
|
||||
</p> */}
|
||||
</div>
|
||||
<TextFieldWide name="server" label="Server" placeholder="Address: Eg irc.server.net" required={true} />
|
||||
<NumberFieldWide name="port" label="Port" />
|
||||
|
||||
<div className="py-6 px-6 space-y-6 sm:py-0 sm:space-y-0 sm:divide-y sm:divide-gray-200">
|
||||
<SwitchGroup name="tls" label="TLS"/>
|
||||
<SwitchGroup name="tls" label="TLS" />
|
||||
</div>
|
||||
|
||||
<TextFieldWide name="nick" label="Nick" placeholder="Nick" required={true} />
|
||||
<PasswordFieldWide name="pass" label="Password" help="Network password" />
|
||||
|
||||
<TextFieldWide name="password" label="Password" placeholder="Network password" />
|
||||
<div className="px-6 space-y-1 border-t pt-6">
|
||||
<Dialog.Title className="text-lg font-medium text-gray-900">Account</Dialog.Title>
|
||||
{/* <p className="text-sm text-gray-500">
|
||||
Networks, channels and invite commands are configured automatically.
|
||||
</p> */}
|
||||
</div>
|
||||
|
||||
<TextAreaWide name="connect_commands" label="Connect commands" placeholder="/msg test this" />
|
||||
<TextFieldWide name="nickserv.account" label="NickServ Account" required={true} />
|
||||
<PasswordFieldWide name="nickserv.password" label="NickServ Password" />
|
||||
|
||||
|
||||
{/* <Field*/}
|
||||
{/* name="sasl.mechanism"*/}
|
||||
{/* type="select"*/}
|
||||
{/* render={({input}) => (*/}
|
||||
{/* <Listbox value={input.value} onChange={input.onChange}>*/}
|
||||
{/* {({open}) => (*/}
|
||||
{/* <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>*/}
|
||||
{/* <Listbox.Label className="block text-sm font-medium text-gray-900 sm:mt-px sm:pt-2">SASL / auth</Listbox.Label>*/}
|
||||
{/* </div>*/}
|
||||
{/* <div className="sm:col-span-2 relative">*/}
|
||||
{/* <Listbox.Button*/}
|
||||
{/* className="bg-white relative w-full border border-gray-300 rounded-md shadow-sm pl-3 pr-10 py-2 text-left cursor-default focus:outline-none focus:ring-1 focus:ring-indigo-500 focus:border-indigo-500 sm:text-sm">*/}
|
||||
{/* <span className="block truncate">{input.value ? saslTypeOptions.find(c => c.value === input.value)!.label : "Choose a auth type"}</span>*/}
|
||||
{/* /!*<span className="block truncate">Choose a auth type</span>*!/*/}
|
||||
{/* <span*/}
|
||||
{/* className="absolute inset-y-0 right-0 flex items-center pr-2 pointer-events-none">*/}
|
||||
{/* <SelectorIcon className="h-5 w-5 text-gray-400" aria-hidden="true"/>*/}
|
||||
{/*</span>*/}
|
||||
{/* </Listbox.Button>*/}
|
||||
|
||||
{/* <Transition*/}
|
||||
{/* show={open}*/}
|
||||
{/* as={Fragment}*/}
|
||||
{/* leave="transition ease-in duration-100"*/}
|
||||
{/* leaveFrom="opacity-100"*/}
|
||||
{/* leaveTo="opacity-0"*/}
|
||||
{/* >*/}
|
||||
{/* <Listbox.Options*/}
|
||||
{/* static*/}
|
||||
{/* className="absolute z-10 mt-1 w-full bg-white shadow-lg max-h-60 rounded-md py-1 text-base ring-1 ring-black ring-opacity-5 overflow-auto focus:outline-none sm:text-sm"*/}
|
||||
{/* >*/}
|
||||
{/* {saslTypeOptions.map((opt: any) => (*/}
|
||||
{/* <Listbox.Option*/}
|
||||
{/* key={opt.value}*/}
|
||||
{/* className={({active}) =>*/}
|
||||
{/* classNames(*/}
|
||||
{/* active ? 'text-white bg-indigo-600' : 'text-gray-900',*/}
|
||||
{/* 'cursor-default select-none relative py-2 pl-3 pr-9'*/}
|
||||
{/* )*/}
|
||||
{/* }*/}
|
||||
{/* value={opt.value}*/}
|
||||
{/* >*/}
|
||||
{/* {({selected, active}) => (*/}
|
||||
{/* <>*/}
|
||||
{/* <span className={classNames(selected ? 'font-semibold' : 'font-normal', 'block truncate')}>*/}
|
||||
{/* {opt.label}*/}
|
||||
{/* </span>*/}
|
||||
|
||||
{/* {selected ? (*/}
|
||||
{/* <span*/}
|
||||
{/* className={classNames(*/}
|
||||
{/* active ? 'text-white' : 'text-indigo-600',*/}
|
||||
{/* 'absolute inset-y-0 right-0 flex items-center pr-4'*/}
|
||||
{/* )}*/}
|
||||
{/* >*/}
|
||||
{/* <CheckIcon className="h-5 w-5" aria-hidden="true"/>*/}
|
||||
{/* </span>*/}
|
||||
{/* ) : null}*/}
|
||||
{/* </>*/}
|
||||
{/* )}*/}
|
||||
{/* </Listbox.Option>*/}
|
||||
{/* ))}*/}
|
||||
{/* </Listbox.Options>*/}
|
||||
{/* </Transition>*/}
|
||||
{/* </div>*/}
|
||||
{/* </div>*/}
|
||||
{/* )}*/}
|
||||
{/* </Listbox>*/}
|
||||
{/* )} />*/}
|
||||
<PasswordFieldWide name="invite_command" label="Invite command" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -294,7 +222,7 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
onClick={() => fields.remove(index)}
|
||||
>
|
||||
<span className="sr-only">Remove</span>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true"/>
|
||||
<XIcon className="h-6 w-6" aria-hidden="true" />
|
||||
</button>
|
||||
</div>
|
||||
))
|
||||
|
@ -337,7 +265,7 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
<button
|
||||
type="submit"
|
||||
disabled={pristine || invalid}
|
||||
className={classNames(pristine || invalid ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700","inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500")}
|
||||
className={classNames(pristine || invalid ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700", "inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500")}
|
||||
>
|
||||
Save
|
||||
</button>
|
||||
|
@ -345,27 +273,7 @@ function IrcNetworkUpdateForm({isOpen, toggle, network}: any) {
|
|||
</div>
|
||||
</div>
|
||||
|
||||
{/*<div*/}
|
||||
{/* className="flex-shrink-0 px-4 border-t border-gray-200 py-5 sm:px-6">*/}
|
||||
{/* <div className="space-x-3 flex justify-end">*/}
|
||||
{/* <button*/}
|
||||
{/* type="button"*/}
|
||||
{/* className="bg-white py-2 px-4 border border-gray-300 rounded-md shadow-sm text-sm font-medium text-gray-700 hover:bg-gray-50 focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500"*/}
|
||||
{/* onClick={toggle}*/}
|
||||
{/* >*/}
|
||||
{/* Cancel*/}
|
||||
{/* </button>*/}
|
||||
{/* <button*/}
|
||||
{/* type="submit"*/}
|
||||
{/* disabled={pristine || invalid}*/}
|
||||
{/* className={classNames(pristine || invalid ? "bg-indigo-300" : "bg-indigo-600 hover:bg-indigo-700","inline-flex justify-center py-2 px-4 border border-transparent shadow-sm text-sm font-medium rounded-md text-white focus:outline-none focus:ring-2 focus:ring-offset-2 focus:ring-indigo-500")}*/}
|
||||
{/* >*/}
|
||||
{/* Save*/}
|
||||
{/* </button>*/}
|
||||
{/* </div>*/}
|
||||
{/*</div>*/}
|
||||
|
||||
<DEBUG values={values}/>
|
||||
<DEBUG values={values} />
|
||||
</form>
|
||||
)
|
||||
}}
|
||||
|
|
|
@ -82,7 +82,7 @@ function IrcSettings() {
|
|||
scope="col"
|
||||
className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider"
|
||||
>
|
||||
Addr
|
||||
Server
|
||||
</th>
|
||||
<th
|
||||
scope="col"
|
||||
|
@ -138,8 +138,8 @@ const ListItem = ({ idx, network }: any) => {
|
|||
</Switch>
|
||||
</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium text-gray-900">{network.name}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{network.addr} {network.tls && <span className="ml-2 inline-flex items-center px-2 py-0.5 rounded text-xs font-medium bg-green-100 text-green-800">TLS</span>}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{network.nick}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{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 text-green-800">TLS</span>}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{network.nickserv?.account}</td>
|
||||
<td className="px-6 py-4 whitespace-nowrap text-right text-sm font-medium">
|
||||
<span className="text-indigo-600 hover:text-indigo-900 cursor-pointer" onClick={toggleUpdate}>
|
||||
Edit
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue