diff --git a/src/components/resource-target-address-item.tsx b/src/components/resource-target-address-item.tsx index dfefc3bf2..851b64b54 100644 --- a/src/components/resource-target-address-item.tsx +++ b/src/components/resource-target-address-item.tsx @@ -23,6 +23,7 @@ import { import { Input } from "./ui/input"; import { Popover, PopoverContent, PopoverTrigger } from "./ui/popover"; import { Select, SelectContent, SelectItem, SelectTrigger } from "./ui/select"; +import { SitesSelector } from "./site-selector"; type SiteWithUpdateAvailable = ListSitesResponse["sites"][number]; @@ -54,16 +55,6 @@ export function ResourceTargetAddressItem({ }: ResourceTargetAddressItemProps) { const t = useTranslations(); - const [siteSearchQuery, setSiteSearchQuery] = useState(""); - - const { data: sites = [] } = useQuery( - orgQueries.sites({ - orgId, - query: siteSearchQuery, - perPage: 10 - }) - ); - const [selectedSite, setSelectedSite] = useState { - const allSites: Array< - Pick - > = [...sites]; - if ( - selectedSite !== null && - !( - allSites.find((site) => site.siteId)?.siteId === - selectedSite?.siteId - ) - ) { - allSites.unshift(selectedSite); - } - return allSites; - }, [sites, selectedSite]); - const handleContainerSelectForTarget = ( hostname: string, port?: number @@ -150,47 +125,18 @@ export function ResourceTargetAddressItem({ - - setSiteSearchQuery(v)} - /> - - {t("siteNotFound")} - - {sitesShown.map((site) => ( - { - updateTarget( - proxyTarget.targetId, - { - siteId: site.siteId, - siteType: site.type, - siteName: site.name - } - ); - - setSelectedSite(site); - }} - > - - {site.name} - - ))} - - - + { + updateTarget(proxyTarget.targetId, { + siteId: site.siteId, + siteType: site.type, + siteName: site.name + }); + setSelectedSite(site); + }} + /> diff --git a/src/components/site-selector.tsx b/src/components/site-selector.tsx new file mode 100644 index 000000000..9b7d44034 --- /dev/null +++ b/src/components/site-selector.tsx @@ -0,0 +1,91 @@ +import { orgQueries } from "@app/lib/queries"; +import type { ListSitesResponse } from "@server/routers/site"; +import { useQuery } from "@tanstack/react-query"; +import { useMemo, useState } from "react"; +import { + Command, + CommandEmpty, + CommandGroup, + CommandInput, + CommandItem, + CommandList +} from "./ui/command"; +import { cn } from "@app/lib/cn"; +import { CheckIcon } from "lucide-react"; +import { useTranslations } from "next-intl"; +import { useDebounce } from "use-debounce"; + +type Selectedsite = Pick< + ListSitesResponse["sites"][number], + "name" | "siteId" | "type" +>; + +export type SitesSelectorProps = { + orgId: string; + selectedSite?: Selectedsite | null; + onSelectSite: (selected: Selectedsite) => void; +}; + +export function SitesSelector({ + orgId, + selectedSite, + onSelectSite +}: SitesSelectorProps) { + const t = useTranslations(); + const [siteSearchQuery, setSiteSearchQuery] = useState(""); + const [debouncedQuery] = useDebounce(siteSearchQuery, 150); + + const { data: sites = [] } = useQuery( + orgQueries.sites({ + orgId, + query: debouncedQuery, + perPage: 10 + }) + ); + + // always include the selected site in the list of sites shown + const sitesShown = useMemo(() => { + const allSites: Array = [...sites]; + if ( + selectedSite && + !allSites.find((site) => site.siteId === selectedSite?.siteId) + ) { + allSites.unshift(selectedSite); + } + return allSites; + }, [sites, selectedSite]); + + return ( + + setSiteSearchQuery(v)} + /> + + {t("siteNotFound")} + + {sitesShown.map((site) => ( + { + onSelectSite(site); + }} + > + + {site.name} + + ))} + + + + ); +}