diff --git a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx index 822d95f3..7c90789a 100644 --- a/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx +++ b/src/app/[orgId]/settings/resources/[niceId]/proxy/page.tsx @@ -1007,14 +1007,9 @@ export default function ReverseProxyTargets(props: { ) => { updateTarget(row.original.targetId, { ...row.original, - ip: hostname + ip: hostname, + ...(port && { port: port }) }); - if (port) { - updateTarget(row.original.targetId, { - ...row.original, - port: port - }); - } }; return ( diff --git a/src/app/[orgId]/settings/resources/create/page.tsx b/src/app/[orgId]/settings/resources/create/page.tsx index 62aab8e2..92413149 100644 --- a/src/app/[orgId]/settings/resources/create/page.tsx +++ b/src/app/[orgId]/settings/resources/create/page.tsx @@ -58,7 +58,16 @@ import { } from "@app/components/ui/popover"; import { CaretSortIcon, CheckIcon } from "@radix-ui/react-icons"; import { cn } from "@app/lib/cn"; -import { ArrowRight, CircleCheck, CircleX, Info, MoveRight, Plus, Settings, SquareArrowOutUpRight } from "lucide-react"; +import { + ArrowRight, + CircleCheck, + CircleX, + Info, + MoveRight, + Plus, + Settings, + SquareArrowOutUpRight +} from "lucide-react"; import CopyTextBox from "@app/components/CopyTextBox"; import Link from "next/link"; import { useTranslations } from "next-intl"; @@ -89,16 +98,25 @@ import { isTargetValid } from "@server/lib/validators"; import { ListTargetsResponse } from "@server/routers/target"; import { DockerManager, DockerState } from "@app/lib/docker"; import { parseHostTarget } from "@app/lib/parseHostTarget"; -import { toASCII, toUnicode } from 'punycode'; +import { toASCII, toUnicode } from "punycode"; import { DomainRow } from "../../../../../components/DomainsTable"; import { finalizeSubdomainSanitize } from "@app/lib/subdomain-utils"; -import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@app/components/ui/tooltip"; -import { PathMatchDisplay, PathMatchModal, PathRewriteDisplay, PathRewriteModal } from "@app/components/PathMatchRenameModal"; +import { + Tooltip, + TooltipContent, + TooltipProvider, + TooltipTrigger +} from "@app/components/ui/tooltip"; +import { + PathMatchDisplay, + PathMatchModal, + PathRewriteDisplay, + PathRewriteModal +} from "@app/components/PathMatchRenameModal"; import { Badge } from "@app/components/ui/badge"; import HealthCheckDialog from "@app/components/HealthCheckDialog"; import { SwitchInput } from "@app/components/SwitchInput"; - const baseResourceFormSchema = z.object({ name: z.string().min(1).max(255), http: z.boolean() @@ -119,50 +137,57 @@ const targetsSettingsSchema = z.object({ stickySession: z.boolean() }); - -const addTargetSchema = z.object({ - ip: z.string().refine(isTargetValid), - method: z.string().nullable(), - port: z.coerce.number().int().positive(), - siteId: z.number().int().positive(), - path: z.string().optional().nullable(), - pathMatchType: z.enum(["exact", "prefix", "regex"]).optional().nullable(), - rewritePath: z.string().optional().nullable(), - rewritePathType: z.enum(["exact", "prefix", "regex", "stripPrefix"]).optional().nullable(), - priority: z.number().int().min(1).max(1000) -}).refine( - (data) => { - // If path is provided, pathMatchType must be provided - if (data.path && !data.pathMatchType) { - return false; - } - // If pathMatchType is provided, path must be provided - if (data.pathMatchType && !data.path) { - return false; - } - // Validate path based on pathMatchType - if (data.path && data.pathMatchType) { - switch (data.pathMatchType) { - case "exact": - case "prefix": - // Path should start with / - return data.path.startsWith("/"); - case "regex": - // Validate regex - try { - new RegExp(data.path); - return true; - } catch { - return false; - } +const addTargetSchema = z + .object({ + ip: z.string().refine(isTargetValid), + method: z.string().nullable(), + port: z.coerce.number().int().positive(), + siteId: z.number().int().positive(), + path: z.string().optional().nullable(), + pathMatchType: z + .enum(["exact", "prefix", "regex"]) + .optional() + .nullable(), + rewritePath: z.string().optional().nullable(), + rewritePathType: z + .enum(["exact", "prefix", "regex", "stripPrefix"]) + .optional() + .nullable(), + priority: z.number().int().min(1).max(1000) + }) + .refine( + (data) => { + // If path is provided, pathMatchType must be provided + if (data.path && !data.pathMatchType) { + return false; } + // If pathMatchType is provided, path must be provided + if (data.pathMatchType && !data.path) { + return false; + } + // Validate path based on pathMatchType + if (data.path && data.pathMatchType) { + switch (data.pathMatchType) { + case "exact": + case "prefix": + // Path should start with / + return data.path.startsWith("/"); + case "regex": + // Validate regex + try { + new RegExp(data.path); + return true; + } catch { + return false; + } + } + } + return true; + }, + { + message: "Invalid path configuration" } - return true; - }, - { - message: "Invalid path configuration" - } -) + ) .refine( (data) => { // If rewritePath is provided, rewritePathType must be provided @@ -221,7 +246,9 @@ export default function Page() { // Target management state const [targets, setTargets] = useState([]); const [targetsToRemove, setTargetsToRemove] = useState([]); - const [dockerStates, setDockerStates] = useState>(new Map()); + const [dockerStates, setDockerStates] = useState>( + new Map() + ); const [selectedTargetForHealthCheck, setSelectedTargetForHealthCheck] = useState(null); @@ -290,12 +317,12 @@ export default function Page() { ...(!env.flags.allowRawResources ? [] : [ - { - id: "raw" as ResourceType, - title: t("resourceRaw"), - description: t("resourceRawDescription") - } - ]) + { + id: "raw" as ResourceType, + title: t("resourceRaw"), + description: t("resourceRawDescription") + } + ]) ]; const baseForm = useForm({ @@ -330,7 +357,7 @@ export default function Page() { pathMatchType: null, rewritePath: null, rewritePathType: null, - priority: 100, + priority: 100 } as z.infer }); @@ -360,14 +387,14 @@ export default function Page() { const dockerManager = new DockerManager(api, siteId); const dockerState = await dockerManager.initializeDocker(); - setDockerStates(prev => new Map(prev.set(siteId, dockerState))); + setDockerStates((prev) => new Map(prev.set(siteId, dockerState))); }; const refreshContainersForSite = async (siteId: number) => { const dockerManager = new DockerManager(api, siteId); const containers = await dockerManager.fetchContainers(); - setDockerStates(prev => { + setDockerStates((prev) => { const newMap = new Map(prev); const existingState = newMap.get(siteId); if (existingState) { @@ -378,11 +405,13 @@ export default function Page() { }; const getDockerStateForSite = (siteId: number): DockerState => { - return dockerStates.get(siteId) || { - isEnabled: false, - isAvailable: false, - containers: [] - }; + return ( + dockerStates.get(siteId) || { + isEnabled: false, + isAvailable: false, + containers: [] + } + ); }; async function addTarget(data: z.infer) { @@ -443,7 +472,7 @@ export default function Page() { pathMatchType: null, rewritePath: null, rewritePathType: null, - priority: 100, + priority: 100 }); } @@ -463,11 +492,11 @@ export default function Page() { targets.map((target) => target.targetId === targetId ? { - ...target, - ...data, - updated: true, - // siteType: site?.type || null - } + ...target, + ...data, + updated: true + // siteType: site?.type || null + } : target ) ); @@ -497,7 +526,9 @@ export default function Page() { : undefined; Object.assign(payload, { - subdomain: sanitizedSubdomain ? toASCII(sanitizedSubdomain) : undefined, + subdomain: sanitizedSubdomain + ? toASCII(sanitizedSubdomain) + : undefined, domainId: httpData.domainId, protocol: "tcp" }); @@ -660,7 +691,7 @@ export default function Page() { const rawDomains = res.data.data.domains as DomainRow[]; const domains = rawDomains.map((domain) => ({ ...domain, - baseDomain: toUnicode(domain.baseDomain), + baseDomain: toUnicode(domain.baseDomain) })); setBaseDomains(domains); // if (domains.length) { @@ -683,10 +714,10 @@ export default function Page() { targets.map((target) => target.targetId === targetId ? { - ...target, - ...config, - updated: true - } + ...target, + ...config, + updated: true + } : target ) ); @@ -712,9 +743,7 @@ export default function Page() { -

- {t("priorityDescription")} -

+

{t("priorityDescription")}

@@ -895,19 +924,39 @@ export default function Page() { ) => { updateTarget(row.original.targetId, { ...row.original, - ip: hostname + ip: hostname, + ...(port && { port: port }) }); - if (port) { - updateTarget(row.original.targetId, { - ...row.original, - port: port - }); - } }; return (
+ {selectedSite && + selectedSite.type === "newt" && + (() => { + const dockerState = getDockerStateForSite( + selectedSite.siteId + ); + return ( + + refreshContainersForSite( + selectedSite.siteId + ) + } + /> + ); + })()} +