diff --git a/src-web/components/Dropdown.tsx b/src-web/components/Dropdown.tsx index 210eeae7..e07f375c 100644 --- a/src-web/components/Dropdown.tsx +++ b/src-web/components/Dropdown.tsx @@ -2,7 +2,16 @@ import * as DropdownMenu from '@radix-ui/react-dropdown-menu'; import { DropdownMenuRadioGroup } from '@radix-ui/react-dropdown-menu'; import { motion } from 'framer-motion'; import { CheckIcon } from '@radix-ui/react-icons'; -import { forwardRef, HTMLAttributes, ReactNode } from 'react'; +import { + ForwardedRef, + forwardRef, + HTMLAttributes, + ReactNode, + useEffect, + useImperativeHandle, + useMemo, + useRef, +} from 'react'; import classnames from 'classnames'; interface DropdownMenuRadioProps { @@ -51,11 +60,15 @@ export function DropdownMenuRadio({ export interface DropdownProps { children: ReactNode; - items: { - label: string; - onSelect?: () => void; - disabled?: boolean; - }[]; + items: ( + | { + label: string; + onSelect?: () => void; + disabled?: boolean; + leftSlot?: ReactNode; + } + | '-----' + )[]; } export function Dropdown({ children, items }: DropdownProps) { @@ -64,11 +77,22 @@ export function Dropdown({ children, items }: DropdownProps) { {children} - {items.map((item, i) => ( - item.onSelect?.()} disabled={item.disabled}> - {item.label} - - ))} + {items.map((item, i) => { + if (item === '-----') { + return ; + } else { + return ( + item.onSelect?.()} + disabled={item.disabled} + leftSlot={item.leftSlot} + > + {item.label} + + ); + } + })} @@ -94,13 +118,25 @@ function DropdownMenuPortal({ children }: DropdownMenuPortalProps) { const DropdownMenuContent = forwardRef( function DropdownMenuContent( { className, children, ...props }: DropdownMenu.DropdownMenuContentProps, - ref, + ref: ForwardedRef, ) { + const divRef = useRef(null); + useImperativeHandle(ref, () => divRef.current); + + // Calculate the max height so we can scroll + const styles = useMemo(() => { + if (divRef.current === null) return; + const windowBox = document.documentElement.getBoundingClientRect(); + const menuBox = divRef.current.getBoundingClientRect(); + return { maxHeight: windowBox.height - menuBox.top - 5 }; + }, [divRef.current]); + return ( {children} @@ -216,14 +252,14 @@ function DropdownMenuLabel({ className, children, ...props }: DropdownMenu.Dropd ); } -// function DropdownMenuSeparator({ className, ...props }: DropdownMenu.DropdownMenuSeparatorProps) { -// return ( -// -// ); -// } +function DropdownMenuSeparator({ className, ...props }: DropdownMenu.DropdownMenuSeparatorProps) { + return ( + + ); +} function DropdownMenuTrigger({ children, diff --git a/src-web/components/Icon.tsx b/src-web/components/Icon.tsx index ce2cbc1a..18838cc3 100644 --- a/src-web/components/Icon.tsx +++ b/src-web/components/Icon.tsx @@ -1,10 +1,12 @@ import { ArchiveIcon, CameraIcon, + CheckIcon, GearIcon, HomeIcon, MoonIcon, PaperPlaneIcon, + QuestionMarkIcon, SunIcon, TriangleDownIcon, UpdateIcon, @@ -20,6 +22,8 @@ type IconName = | 'triangle-down' | 'paper-plane' | 'update' + | 'question' + | 'check' | 'sun' | 'moon'; @@ -28,11 +32,13 @@ const icons: Record> = { 'triangle-down': TriangleDownIcon, archive: ArchiveIcon, camera: CameraIcon, + check: CheckIcon, gear: GearIcon, home: HomeIcon, update: UpdateIcon, sun: SunIcon, moon: MoonIcon, + question: QuestionMarkIcon, }; export interface IconProps { @@ -43,7 +49,7 @@ export interface IconProps { } export function Icon({ icon, spin, size = 'md', className }: IconProps) { - const Component = icons[icon]; + const Component = icons[icon] ?? icons.question; return ( (null); const responses = useResponses(requestId); - const response = responses.data[0]; + const response = activeResponseId + ? responses.data.find((r) => r.id === activeResponseId) + : responses.data[0]; const deleteResponse = useDeleteResponse(response); const deleteAllResponses = useDeleteAllResponses(response?.requestId); + useEffect(() => { + setActiveResponseId(null); + }, [responses.data?.length]); + const contentType = useMemo( () => response?.headers.find((h) => h.name.toLowerCase() === 'content-type')?.value ?? 'text/plain', @@ -47,6 +55,12 @@ export function ResponsePane({ requestId, error }: Props) { onSelect: deleteAllResponses.mutate, disabled: responses.data.length === 0, }, + '-----', + ...responses.data.map((r) => ({ + label: r.status + ' - ' + r.elapsed, + leftSlot: response?.id === r.id ? : <>, + onSelect: () => setActiveResponseId(r.id), + })), ]} >