address input design

This commit is contained in:
Pallavi Kumari
2025-10-09 00:53:45 +05:30
parent 0a377150e3
commit a6086d3724

View File

@@ -860,17 +860,14 @@ export default function ReverseProxyTargets(props: {
} }
}, },
{ {
accessorKey: "siteId", accessorKey: "address",
header: t("site"), header: t("address"),
cell: ({ row }) => { cell: ({ row }) => {
const selectedSite = sites.find( const selectedSite = sites.find(
(site) => site.siteId === row.original.siteId (site) => site.siteId === row.original.siteId
); );
const handleContainerSelectForTarget = ( const handleContainerSelectForTarget = (hostname: string, port?: number) => {
hostname: string,
port?: number
) => {
updateTarget(row.original.targetId, { updateTarget(row.original.targetId, {
...row.original, ...row.original,
ip: hostname ip: hostname
@@ -884,67 +881,53 @@ export default function ReverseProxyTargets(props: {
}; };
return ( return (
<div className="flex gap-1 items-center"> <div className="flex items-center gap-1">
<Popover> <Button variant={"outline"} className="w-full justify-start py-0 space-x-2 px-0 hover:bg-card cursor-default">
<PopoverTrigger asChild> <Popover>
<Button <PopoverTrigger asChild>
variant="outline" <Button
role="combobox" variant="ghost"
className={cn( role="combobox"
"justify-between flex-1", className={cn(
!row.original.siteId && "min-w-[90px] justify-between text-sm font-medium border-r pr-4 rounded-none h-8 hover:bg-transparent",
"text-muted-foreground" !row.original.siteId && "text-muted-foreground"
)} )}
> >
{row.original.siteId {row.original.siteId ? selectedSite?.name : t("siteSelect")}
? selectedSite?.name <CaretSortIcon className="ml-2h-4 w-4 shrink-0 opacity-50" />
: t("siteSelect")} </Button>
<CaretSortIcon className="ml-2 h-4 w-4 shrink-0 opacity-50" /> </PopoverTrigger>
</Button> <PopoverContent className="p-0 w-[180px]">
</PopoverTrigger> <Command>
<PopoverContent className="p-0"> <CommandInput placeholder={t("siteSearch")} />
<Command> <CommandList>
<CommandInput <CommandEmpty>{t("siteNotFound")}</CommandEmpty>
placeholder={t("siteSearch")} <CommandGroup>
/> {sites.map((site) => (
<CommandList> <CommandItem
<CommandEmpty> key={site.siteId}
{t("siteNotFound")} value={`${site.siteId}:${site.name}`}
</CommandEmpty> onSelect={() =>
<CommandGroup> updateTarget(row.original.targetId, { siteId: site.siteId })
{sites.map((site) => ( }
<CommandItem >
value={`${site.siteId}:${site.name}:${site.niceId}`} <CheckIcon
key={site.siteId} className={cn(
onSelect={() => { "mr-2 h-4 w-4",
updateTarget( site.siteId === row.original.siteId
row.original ? "opacity-100"
.targetId, : "opacity-0"
{ )}
siteId: site.siteId />
} {site.name}
); </CommandItem>
}} ))}
> </CommandGroup>
<CheckIcon </CommandList>
className={cn( </Command>
"mr-2 h-4 w-4", </PopoverContent>
site.siteId === </Popover>
row.original {selectedSite &&
.siteId
? "opacity-100"
: "opacity-0"
)}
/>
{site.name}
</CommandItem>
))}
</CommandGroup>
</CommandList>
</Command>
</PopoverContent>
</Popover>
{selectedSite &&
selectedSite.type === "newt" && selectedSite.type === "newt" &&
(() => { (() => {
const dockerState = getDockerStateForSite( const dockerState = getDockerStateForSite(
@@ -966,70 +949,84 @@ export default function ReverseProxyTargets(props: {
/> />
); );
})()} })()}
</div>
);
}
},
{
accessorKey: "target",
header: t("target"),
cell: ({ row }) => {
const hasTarget = !!(row.original.ip || row.original.port || row.original.method);
return hasTarget ? ( <Select
<div className="flex items-center gap-1"> defaultValue={row.original.method ?? "http"}
<TargetModal onValueChange={(value) =>
value={{ updateTarget(row.original.targetId, {
method: row.original.method, ...row.original,
ip: row.original.ip, method: value,
port: row.original.port })
}} }
onChange={(config) => >
updateTarget(row.original.targetId, { <SelectTrigger className="h-8 px-2 w-[70px] text-sm font-normal border-none bg-transparent shadow-none focus:ring-0 focus:outline-none focus-visible:ring-0 data-[state=open]:bg-transparent">
...row.original, {row.original.method || "http"}
...config </SelectTrigger>
}) <SelectContent>
} <SelectItem value="http">http</SelectItem>
showMethod={resource.http} <SelectItem value="https">https</SelectItem>
trigger={ <SelectItem value="h2c">h2c</SelectItem>
<Button </SelectContent>
variant="outline" </Select>
className="flex items-center gap-2 max-w-md text-left cursor-pointer"
> <div className="flex items-center justify-center bg-gray-400 text-black px-1 h-9">
<TargetDisplay {"://"}
value={{ </div>
method: row.original.method,
ip: row.original.ip, <Input
port: row.original.port defaultValue={row.original.ip}
}} placeholder="IP / Hostname"
showMethod={resource.http} className="min-w-[130px] border-none placeholder-gray-400"
/> onBlur={(e) => {
</Button> const input = e.target.value.trim();
} const hasProtocol = /^(https?|h2c):\/\//.test(input);
/> const hasPort = /:\d+(?:\/|$)/.test(input);
<MoveRight className="mr-2 h-4 w-4" />
if (hasProtocol || hasPort) {
const parsed = parseHostTarget(input);
if (parsed) {
updateTarget(row.original.targetId, {
...row.original,
method: hasProtocol
? parsed.protocol
: row.original.method,
ip: parsed.host,
port: hasPort
? parsed.port
: row.original.port
});
} else {
updateTarget(row.original.targetId, {
...row.original,
ip: input
});
}
} else {
updateTarget(row.original.targetId, {
...row.original,
ip: input
});
}
}}
/>
<div className="flex items-center justify-center bg-gray-400 text-black px-1 h-9">
{":"}
</div>
<Input
type="number"
placeholder="Port"
defaultValue={row.original.port}
className="min-w-[60px] pl-0 border-none placeholder-gray-400"
onBlur={(e) =>
updateTarget(row.original.targetId, {
...row.original,
port: parseInt(e.target.value, 10)
})
}
/>
</Button>
<MoveRight className="ml-1 h-4 w-4" />
</div> </div>
) : (
<TargetModal
value={{
method: row.original.method,
ip: row.original.ip,
port: row.original.port
}}
onChange={(config) =>
updateTarget(row.original.targetId, {
...row.original,
...config
})
}
showMethod={resource.http}
trigger={
<Button variant="outline">
<Plus className="h-4 w-4 mr-2" />
{t("configureTarget")}
</Button>
}
/>
); );
} }
}, },