From d3419713c82922c560ef54eace9f91cc2ac10e68 Mon Sep 17 00:00:00 2001 From: Xevion Date: Fri, 25 Aug 2023 23:55:32 -0500 Subject: [PATCH] Add manual target type selection ListBox, add targetType to onChange return, autodetect interface --- src/components/form/LookupInput.tsx | 142 ++++++++++++++++++++++++++-- src/pages/index.tsx | 2 +- 2 files changed, 135 insertions(+), 9 deletions(-) diff --git a/src/components/form/LookupInput.tsx b/src/components/form/LookupInput.tsx index 19c70d5..cedcaec 100644 --- a/src/components/form/LookupInput.tsx +++ b/src/components/form/LookupInput.tsx @@ -1,8 +1,15 @@ import { useForm } from "react-hook-form"; import type { FunctionComponent } from "react"; -import { onPromise, preventDefault } from "@/helpers"; +import { Fragment, useState } from "react"; +import { classNames, onPromise, preventDefault } from "@/helpers"; import type { SubmitProps, TargetType } from "@/types"; -import { MagnifyingGlassIcon } from "@heroicons/react/20/solid"; +import { ObjectType } from "@/types"; +import { + CheckIcon, + ChevronUpDownIcon, + MagnifyingGlassIcon, +} from "@heroicons/react/20/solid"; +import { Listbox, Transition } from "@headlessui/react"; type LookupInputProps = { isLoading?: boolean; @@ -10,7 +17,7 @@ type LookupInputProps = { onRegistry?: (type: TargetType) => Promise; // When a user hits submit, this is called. onSubmit?: (props: SubmitProps) => Promise; - onChange?: (target: string) => any; + onChange?: (target: { target: string; targetType: ObjectType | null }) => any; }; const LookupInput: FunctionComponent = ({ @@ -26,6 +33,36 @@ const LookupInput: FunctionComponent = ({ }, }); + const options: Record = { + auto: "Autodetect", + domain: "Domain", + ip: "IP/CIDR", + tld: "TLD", + autnum: "AS Number", + entity: "Entity Handle", + registrar: "Registrar", + url: "URL", + json: "JSON", + }; + + const [selected, setSelected] = useState("auto"); + + function getAutoTargetText(): string { + return "Autodetect"; + } + + /* + * Returns the type of object that the user has selected. Handles the extra "auto" option like null. + * @param value The value of the select element. + */ + function getTargetType(value?: string | null): ObjectType | null { + // Pull the value from the select element if it's not provided (useful for eventing values). + if (value == null) value = selected; + + if (value == "auto" || value == null) return null; + else return value as ObjectType; + } + return (
= ({ -
+
= ({ />
{ - if (onChange != undefined) onChange(getValues("target")); + if (onChange != undefined) + onChange({ + target: getValues("target"), + targetType: getTargetType(), + }); }, })} - /> + > + { + setSelected(value); + + if (onChange != undefined) + onChange({ + target: getValues("target"), + targetType: getTargetType(value), + }); + }} + disabled={isLoading} + > +
+ + {/* Fetch special text for 'auto' mode, otherwise just use the options. */} + + {selected == "auto" ? getAutoTargetText() : options[selected]} + + + + + + + {Object.entries(options).map(([key, value]) => ( + + classNames( + "relative cursor-default select-none py-2 pl-10 pr-4", + active ? "bg-zinc-800 text-zinc-300" : null + ) + } + value={key} + > + {({ selected }) => ( + <> + + {value} + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
+
-
+
{
{ + onChange={({ target, targetType }) => { setTarget(target); }} onSubmit={async (props) => {