Trying to get these forms to work

This commit is contained in:
Owen
2026-05-26 21:20:34 -07:00
parent e19b6ebc82
commit cb90672573
11 changed files with 282 additions and 144 deletions

View File

@@ -346,7 +346,7 @@ export const siteResources = pgTable("siteResources", {
niceId: varchar("niceId").notNull(), niceId: varchar("niceId").notNull(),
name: varchar("name").notNull(), name: varchar("name").notNull(),
ssl: boolean("ssl").notNull().default(false), ssl: boolean("ssl").notNull().default(false),
mode: varchar("mode").$type<"host" | "cidr" | "http">().notNull(), // "host" | "cidr" | "http" mode: varchar("mode").$type<"host" | "cidr" | "http" | "ssh">().notNull(), // "host" | "cidr" | "http"
scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode scheme: varchar("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
proxyPort: integer("proxyPort"), // only for port mode proxyPort: integer("proxyPort"), // only for port mode
destinationPort: integer("destinationPort"), // only for port mode destinationPort: integer("destinationPort"), // only for port mode

View File

@@ -380,7 +380,7 @@ export const siteResources = sqliteTable("siteResources", {
niceId: text("niceId").notNull(), niceId: text("niceId").notNull(),
name: text("name").notNull(), name: text("name").notNull(),
ssl: integer("ssl", { mode: "boolean" }).notNull().default(false), ssl: integer("ssl", { mode: "boolean" }).notNull().default(false),
mode: text("mode").$type<"host" | "cidr" | "http">().notNull(), // "host" | "cidr" | "http" mode: text("mode").$type<"host" | "cidr" | "http" | "ssh">().notNull(), // "host" | "cidr" | "http"
scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode scheme: text("scheme").$type<"http" | "https">(), // only for when we are doing https or http mode
proxyPort: integer("proxyPort"), // only for port mode proxyPort: integer("proxyPort"), // only for port mode
destinationPort: integer("destinationPort"), // only for port mode destinationPort: integer("destinationPort"), // only for port mode

View File

@@ -44,7 +44,7 @@ const createSiteResourceSchema = z
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
niceId: z.string().optional(), niceId: z.string().optional(),
// protocol: z.enum(["tcp", "udp"]).optional(), // protocol: z.enum(["tcp", "udp"]).optional(),
mode: z.enum(["host", "cidr", "http"]), mode: z.enum(["host", "cidr", "http", "ssh"]),
ssl: z.boolean().optional(), // only used for http mode ssl: z.boolean().optional(), // only used for http mode
scheme: z.enum(["http", "https"]).optional(), scheme: z.enum(["http", "https"]).optional(),
siteIds: z.array(z.int()).optional(), siteIds: z.array(z.int()).optional(),
@@ -75,7 +75,7 @@ const createSiteResourceSchema = z
.strict() .strict()
.refine( .refine(
(data) => { (data) => {
if (data.mode === "host") { if (data.mode === "host" || data.mode === "ssh") {
// Check if it's a valid IP address using zod (v4 or v6) // Check if it's a valid IP address using zod (v4 or v6)
const isValidIP = z const isValidIP = z
// .union([z.ipv4(), z.ipv6()]) // .union([z.ipv4(), z.ipv6()])
@@ -117,13 +117,24 @@ const createSiteResourceSchema = z
) )
.refine( .refine(
(data) => { (data) => {
if (data.mode !== "http") return true; if (data.mode === "http") {
return ( return (
data.scheme !== undefined && data.scheme !== undefined &&
data.destinationPort !== undefined && data.scheme !== null &&
data.destinationPort >= 1 && data.destinationPort !== undefined &&
data.destinationPort <= 65535 data.destinationPort !== null &&
); data.destinationPort >= 1 &&
data.destinationPort <= 65535
);
} else if (data.mode === "ssh") {
// just check the destinationPort
return (
data.destinationPort === undefined ||
(data.destinationPort !== null &&
data.destinationPort >= 1 &&
data.destinationPort <= 65535)
);
}
}, },
{ {
message: message:
@@ -391,6 +402,15 @@ export async function createSiteResource(
); );
} }
let tcpPortRangeStringAdjusted = tcpPortRangeString;
if (mode === "http") {
tcpPortRangeStringAdjusted = "443,80";
} else if (mode === "ssh") {
tcpPortRangeStringAdjusted = destinationPort
? destinationPort.toString()
: "22";
}
// Create the site resource // Create the site resource
const insertValues: typeof siteResources.$inferInsert = { const insertValues: typeof siteResources.$inferInsert = {
niceId: updatedNiceId!, niceId: updatedNiceId!,
@@ -405,10 +425,12 @@ export async function createSiteResource(
enabled, enabled,
alias: alias ? alias.trim() : null, alias: alias ? alias.trim() : null,
aliasAddress, aliasAddress,
tcpPortRangeString: tcpPortRangeString: tcpPortRangeStringAdjusted,
mode == "http" ? "443,80" : tcpPortRangeString, udpPortRangeString:
udpPortRangeString: mode == "http" ? "" : udpPortRangeString, mode == "http" || mode == "ssh" ? "" : udpPortRangeString,
disableIcmp: disableIcmp || (mode == "http" ? true : false), // default to true for http resources, otherwise false disableIcmp:
disableIcmp ||
(mode == "http" || mode == "ssh" ? true : false), // default to true for http resources, otherwise false
domainId, domainId,
subdomain: finalSubdomain, subdomain: finalSubdomain,
fullDomain fullDomain

View File

@@ -56,7 +56,7 @@ const updateSiteResourceSchema = z
) )
.optional(), .optional(),
// mode: z.enum(["host", "cidr", "port"]).optional(), // mode: z.enum(["host", "cidr", "port"]).optional(),
mode: z.enum(["host", "cidr", "http"]).optional(), mode: z.enum(["host", "cidr", "http", "ssh"]).optional(),
ssl: z.boolean().optional(), ssl: z.boolean().optional(),
scheme: z.enum(["http", "https"]).nullish(), scheme: z.enum(["http", "https"]).nullish(),
// proxyPort: z.int().positive().nullish(), // proxyPort: z.int().positive().nullish(),
@@ -85,7 +85,10 @@ const updateSiteResourceSchema = z
.strict() .strict()
.refine( .refine(
(data) => { (data) => {
if (data.mode === "host" && data.destination) { if (
(data.mode === "host" || data.mode == "ssh") &&
data.destination
) {
const isValidIP = z const isValidIP = z
// .union([z.ipv4(), z.ipv6()]) // .union([z.ipv4(), z.ipv6()])
.union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere .union([z.ipv4()]) // for now lets just do ipv4 until we verify ipv6 works everywhere
@@ -126,15 +129,24 @@ const updateSiteResourceSchema = z
) )
.refine( .refine(
(data) => { (data) => {
if (data.mode !== "http") return true; if (data.mode === "http") {
return ( return (
data.scheme !== undefined && data.scheme !== undefined &&
data.scheme !== null && data.scheme !== null &&
data.destinationPort !== undefined && data.destinationPort !== undefined &&
data.destinationPort !== null && data.destinationPort !== null &&
data.destinationPort >= 1 && data.destinationPort >= 1 &&
data.destinationPort <= 65535 data.destinationPort <= 65535
); );
} else if (data.mode === "ssh") {
// just check the destinationPort
return (
data.destinationPort === undefined ||
(data.destinationPort !== null &&
data.destinationPort >= 1 &&
data.destinationPort <= 65535)
);
}
}, },
{ {
message: message:
@@ -446,6 +458,16 @@ export async function updateSiteResource(
}) })
} }
: {}; : {};
let tcpPortRangeStringAdjusted = tcpPortRangeString;
if (mode === "http") {
tcpPortRangeStringAdjusted = "443,80";
} else if (mode === "ssh") {
tcpPortRangeStringAdjusted = destinationPort
? destinationPort.toString()
: "22";
}
[updatedSiteResource] = await trx [updatedSiteResource] = await trx
.update(siteResources) .update(siteResources)
.set({ .set({
@@ -458,12 +480,14 @@ export async function updateSiteResource(
destinationPort, destinationPort,
enabled, enabled,
alias: alias ? alias.trim() : null, alias: alias ? alias.trim() : null,
tcpPortRangeString: tcpPortRangeString: tcpPortRangeStringAdjusted,
mode == "http" ? "443,80" : tcpPortRangeString,
udpPortRangeString: udpPortRangeString:
mode == "http" ? "" : udpPortRangeString, mode == "http" || mode == "ssh"
? ""
: udpPortRangeString,
disableIcmp: disableIcmp:
disableIcmp || (mode == "http" ? true : false), // default to true for http resources, otherwise false disableIcmp ||
(mode == "http" || mode == "ssh" ? true : false), // default to true for http resources, otherwise false
domainId, domainId,
subdomain: finalSubdomain, subdomain: finalSubdomain,
fullDomain, fullDomain,

View File

@@ -120,7 +120,7 @@ export default async function ClientResourcesPage(
// proxyPort: siteResource.proxyPort, // proxyPort: siteResource.proxyPort,
siteIds: siteResource.siteIds, siteIds: siteResource.siteIds,
destination: siteResource.destination, destination: siteResource.destination,
httpHttpsPort: siteResource.destinationPort ?? null, destinationPort: siteResource.destinationPort ?? null,
alias: siteResource.alias || null, alias: siteResource.alias || null,
aliasAddress: siteResource.aliasAddress || null, aliasAddress: siteResource.aliasAddress || null,
siteNiceIds: siteResource.siteNiceIds, siteNiceIds: siteResource.siteNiceIds,

View File

@@ -83,7 +83,7 @@ export type InternalResourceRow = {
// protocol: string | null; // protocol: string | null;
// proxyPort: number | null; // proxyPort: number | null;
destination: string; destination: string;
httpHttpsPort: number | null; destinationPort: number | null;
alias: string | null; alias: string | null;
aliasAddress: string | null; aliasAddress: string | null;
niceId: string; niceId: string;
@@ -107,7 +107,7 @@ function formatDestinationDisplay(row: InternalResourceRow): string {
return formatSiteResourceDestinationDisplay({ return formatSiteResourceDestinationDisplay({
mode: row.mode, mode: row.mode,
destination: row.destination, destination: row.destination,
httpHttpsPort: row.httpHttpsPort, destinationPort: row.destinationPort,
scheme: row.scheme scheme: row.scheme
}); });
} }

View File

@@ -76,7 +76,7 @@ export default function CreateInternalResourceDialog({
...(data.mode === "http" && { ...(data.mode === "http" && {
scheme: data.scheme, scheme: data.scheme,
ssl: data.ssl ?? false, ssl: data.ssl ?? false,
destinationPort: data.httpHttpsPort ?? undefined, destinationPort: data.destinationPort ?? undefined,
domainId: data.httpConfigDomainId domainId: data.httpConfigDomainId
? data.httpConfigDomainId ? data.httpConfigDomainId
: undefined, : undefined,

View File

@@ -78,7 +78,7 @@ export default function EditInternalResourceDialog({
...(data.mode === "http" && { ...(data.mode === "http" && {
scheme: data.scheme, scheme: data.scheme,
ssl: data.ssl ?? false, ssl: data.ssl ?? false,
destinationPort: data.httpHttpsPort ?? null, destinationPort: data.destinationPort ?? null,
domainId: data.httpConfigDomainId domainId: data.httpConfigDomainId
? data.httpConfigDomainId ? data.httpConfigDomainId
: undefined, : undefined,

View File

@@ -54,6 +54,7 @@ import {
MultiSitesSelector, MultiSitesSelector,
formatMultiSitesSelectorLabel formatMultiSitesSelectorLabel
} from "./multi-site-selector"; } from "./multi-site-selector";
import { SitesSelector } from "./site-selector";
import type { Selectedsite } from "./site-selector"; import type { Selectedsite } from "./site-selector";
import { MachinesSelector } from "./machines-selector"; import { MachinesSelector } from "./machines-selector";
@@ -154,7 +155,7 @@ export type InternalResourceData = {
authDaemonMode?: "site" | "remote" | "native" | null; authDaemonMode?: "site" | "remote" | "native" | null;
authDaemonPort?: number | null; authDaemonPort?: number | null;
pamMode?: "passthrough" | "push" | null; pamMode?: "passthrough" | "push" | null;
httpHttpsPort?: number | null; destinationPort?: number | null;
scheme?: "http" | "https" | null; scheme?: "http" | "https" | null;
ssl?: boolean; ssl?: boolean;
subdomain?: string | null; subdomain?: string | null;
@@ -187,7 +188,7 @@ export type InternalResourceFormValues = {
authDaemonMode?: "site" | "remote" | "native" | null; authDaemonMode?: "site" | "remote" | "native" | null;
authDaemonPort?: number | null; authDaemonPort?: number | null;
pamMode?: "passthrough" | "push" | null; pamMode?: "passthrough" | "push" | null;
httpHttpsPort?: number | null; destinationPort?: number | null;
scheme?: "http" | "https"; scheme?: "http" | "https";
ssl?: boolean; ssl?: boolean;
httpConfigSubdomain?: string | null; httpConfigSubdomain?: string | null;
@@ -286,7 +287,7 @@ export function InternalResourceForm({
variant === "create" variant === "create"
? "createInternalResourceDialogAlias" ? "createInternalResourceDialogAlias"
: "editInternalResourceDialogAlias"; : "editInternalResourceDialogAlias";
const httpHttpsPortLabelKey = const destinationPortLabelKey =
variant === "create" variant === "create"
? "createInternalResourceDialogModePort" ? "createInternalResourceDialogModePort"
: "editInternalResourceDialogModePort"; : "editInternalResourceDialogModePort";
@@ -308,16 +309,9 @@ export function InternalResourceForm({
name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)), name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)),
siteIds: siteIdsSchema, siteIds: siteIdsSchema,
mode: z.enum(["host", "cidr", "http", "ssh"]), mode: z.enum(["host", "cidr", "http", "ssh"]),
destination: z destination: z.string(),
.string()
.min(
1,
destinationRequiredKey
? { message: t(destinationRequiredKey) }
: undefined
),
alias: z.string().nullish(), alias: z.string().nullish(),
httpHttpsPort: z destinationPort: z
.number() .number()
.int() .int()
.min(1) .min(1)
@@ -356,6 +350,20 @@ export function InternalResourceForm({
.optional() .optional()
}) })
.superRefine((data, ctx) => { .superRefine((data, ctx) => {
const isNativeSsh =
data.mode === "ssh" && data.authDaemonMode === "native";
if (
!isNativeSsh &&
(!data.destination || data.destination.length < 1)
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: destinationRequiredKey
? t(destinationRequiredKey)
: "Destination is required",
path: ["destination"]
});
}
if (data.mode !== "http") return; if (data.mode !== "http") return;
if (!data.scheme) { if (!data.scheme) {
ctx.addIssue({ ctx.addIssue({
@@ -365,14 +373,15 @@ export function InternalResourceForm({
}); });
} }
if ( if (
data.httpHttpsPort == null || !isNativeSsh &&
!Number.isFinite(data.httpHttpsPort) || (data.destinationPort == null ||
data.httpHttpsPort < 1 !Number.isFinite(data.destinationPort) ||
data.destinationPort < 1)
) { ) {
ctx.addIssue({ ctx.addIssue({
code: z.ZodIssueCode.custom, code: z.ZodIssueCode.custom,
message: t("internalResourceHttpPortRequired"), message: t("internalResourceHttpPortRequired"),
path: ["httpHttpsPort"] path: ["destinationPort"]
}); });
} }
}); });
@@ -523,7 +532,7 @@ export function InternalResourceForm({
: (resource.authDaemonMode ?? "site"), : (resource.authDaemonMode ?? "site"),
authDaemonPort: resource.authDaemonPort ?? null, authDaemonPort: resource.authDaemonPort ?? null,
pamMode: resource.pamMode ?? "passthrough", pamMode: resource.pamMode ?? "passthrough",
httpHttpsPort: resource.httpHttpsPort ?? null, destinationPort: resource.destinationPort ?? null,
scheme: resource.scheme ?? "http", scheme: resource.scheme ?? "http",
ssl: resource.ssl ?? false, ssl: resource.ssl ?? false,
httpConfigSubdomain: resource.subdomain ?? null, httpConfigSubdomain: resource.subdomain ?? null,
@@ -540,7 +549,7 @@ export function InternalResourceForm({
mode: "host", mode: "host",
destination: "", destination: "",
alias: null, alias: null,
httpHttpsPort: null, destinationPort: null,
scheme: "http", scheme: "http",
ssl: true, ssl: true,
httpConfigSubdomain: null, httpConfigSubdomain: null,
@@ -605,7 +614,7 @@ export function InternalResourceForm({
mode: "host", mode: "host",
destination: "", destination: "",
alias: null, alias: null,
httpHttpsPort: null, destinationPort: null,
scheme: "http", scheme: "http",
ssl: true, ssl: true,
httpConfigSubdomain: null, httpConfigSubdomain: null,
@@ -641,7 +650,7 @@ export function InternalResourceForm({
mode: resource.mode ?? "host", mode: resource.mode ?? "host",
destination: resource.destination ?? "", destination: resource.destination ?? "",
alias: resource.alias ?? null, alias: resource.alias ?? null,
httpHttpsPort: resource.httpHttpsPort ?? null, destinationPort: resource.destinationPort ?? null,
scheme: resource.scheme ?? "http", scheme: resource.scheme ?? "http",
ssl: resource.ssl ?? false, ssl: resource.ssl ?? false,
httpConfigSubdomain: resource.subdomain ?? null, httpConfigSubdomain: resource.subdomain ?? null,
@@ -812,56 +821,120 @@ export function InternalResourceForm({
<FormLabel> <FormLabel>
{t("sites")} {t("sites")}
</FormLabel> </FormLabel>
<Popover> {mode === "ssh" &&
<PopoverTrigger asChild> sshServerMode ===
<FormControl> "native" ? (
<Button <Popover>
variant="outline" <PopoverTrigger
role="combobox" asChild
className={cn( >
"w-full justify-between", <FormControl>
selectedSites.length === <Button
0 && variant="outline"
"text-muted-foreground" role="combobox"
)} className={cn(
> "w-full justify-between",
<span className="truncate text-left"> selectedSites.length ===
{formatMultiSitesSelectorLabel( 0 &&
selectedSites, "text-muted-foreground"
t
)} )}
</span> >
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" /> <span className="truncate text-left">
</Button> {selectedSites[0]
</FormControl> ?.name ??
</PopoverTrigger> t(
<PopoverContent className="w-full p-0"> "selectSite"
<MultiSitesSelector )}
orgId={orgId} </span>
selectedSites={ <ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
selectedSites </Button>
} </FormControl>
filterTypes={[ </PopoverTrigger>
"newt" <PopoverContent className="w-full p-0">
]} <SitesSelector
onSelectionChange={( orgId={
sites orgId
) => { }
setSelectedSites( selectedSite={
selectedSites[0] ??
null
}
filterTypes={[
"newt"
]}
onSelectSite={(
site
) => {
setSelectedSites(
[
site
]
);
field.onChange(
[
site.siteId
]
);
}}
/>
</PopoverContent>
</Popover>
) : (
<Popover>
<PopoverTrigger
asChild
>
<FormControl>
<Button
variant="outline"
role="combobox"
className={cn(
"w-full justify-between",
selectedSites.length ===
0 &&
"text-muted-foreground"
)}
>
<span className="truncate text-left">
{formatMultiSitesSelectorLabel(
selectedSites,
t
)}
</span>
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
</Button>
</FormControl>
</PopoverTrigger>
<PopoverContent className="w-full p-0">
<MultiSitesSelector
orgId={
orgId
}
selectedSites={
selectedSites
}
filterTypes={[
"newt"
]}
onSelectionChange={(
sites sites
); ) => {
field.onChange( setSelectedSites(
sites.map( sites
( );
s field.onChange(
) => sites.map(
s.siteId (
) s
); ) =>
}} s.siteId
/> )
</PopoverContent> );
</Popover> }}
/>
</PopoverContent>
</Popover>
)}
<FormMessage /> <FormMessage />
</FormItem> </FormItem>
)} )}
@@ -950,8 +1023,10 @@ export function InternalResourceForm({
"grid gap-4 items-start", "grid gap-4 items-start",
mode === "cidr" && "grid-cols-1", mode === "cidr" && "grid-cols-1",
mode === "http" && "grid-cols-3", mode === "http" && "grid-cols-3",
(mode === "host" || mode === "ssh") && mode === "host" && "grid-cols-2",
"grid-cols-2" mode === "ssh" &&
sshServerMode !== "native" &&
"grid-cols-3"
)} )}
> >
{mode === "http" && ( {mode === "http" && (
@@ -996,7 +1071,11 @@ export function InternalResourceForm({
/> />
</div> </div>
)} )}
{sshServerMode !== "native" && ( {((mode === "ssh" &&
sshServerMode !== "native") ||
mode === "http" ||
mode === "host" ||
mode === "cidr") && (
<div <div
className={cn( className={cn(
mode === "cidr" && "col-span-1", mode === "cidr" && "col-span-1",
@@ -1030,43 +1109,46 @@ export function InternalResourceForm({
/> />
</div> </div>
)} )}
{(mode === "host" || mode === "ssh") && {(mode === "host" ||
sshServerMode !== "native" && ( (mode === "ssh" &&
<div className="min-w-0"> sshServerMode !== "native")) && (
<FormField
control={form.control}
name="alias"
render={({ field }) => (
<FormItem>
<FormLabel>
{t(aliasLabelKey)}
</FormLabel>
<FormControl>
<Input
{...field}
className="w-full"
value={
field.value ??
""
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
)}
{mode === "http" && (
<div className="min-w-0"> <div className="min-w-0">
<FormField <FormField
control={form.control} control={form.control}
name="httpHttpsPort" name="alias"
render={({ field }) => (
<FormItem>
<FormLabel>
{t(aliasLabelKey)}
</FormLabel>
<FormControl>
<Input
{...field}
className="w-full"
value={
field.value ??
""
}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
)}
{(mode === "http" ||
(mode === "ssh" &&
sshServerMode !== "native")) && (
<div className="min-w-0">
<FormField
control={form.control}
name="destinationPort"
render={({ field }) => ( render={({ field }) => (
<FormItem> <FormItem>
<FormLabel> <FormLabel>
{t( {t(
httpHttpsPortLabelKey destinationPortLabelKey
)} )}
</FormLabel> </FormLabel>
<FormControl> <FormControl>
@@ -1690,6 +1772,16 @@ export function InternalResourceForm({
"authDaemonPort", "authDaemonPort",
null null
); );
// Trim to single site
if (selectedSites.length > 1) {
const first =
selectedSites.slice(0, 1);
setSelectedSites(first);
form.setValue(
"siteIds",
first.map((s) => s.siteId)
);
}
} else { } else {
form.setValue( form.setValue(
"authDaemonMode", "authDaemonMode",

View File

@@ -73,7 +73,7 @@ function PrivateResourceMeta({ row }: { row: SiteResourceRow }) {
const dest = formatSiteResourceDestinationDisplay({ const dest = formatSiteResourceDestinationDisplay({
mode: row.mode, mode: row.mode,
destination: row.destination, destination: row.destination,
httpHttpsPort: row.destinationPort ?? null, destinationPort: row.destinationPort ?? null,
scheme: row.scheme scheme: row.scheme
}); });
return ( return (
@@ -149,7 +149,7 @@ function PrivateAccessMethod({ row }: { row: SiteResourceRow }) {
const dest = formatSiteResourceDestinationDisplay({ const dest = formatSiteResourceDestinationDisplay({
mode: row.mode, mode: row.mode,
destination: row.destination, destination: row.destination,
httpHttpsPort: row.destinationPort, destinationPort: row.destinationPort,
scheme: row.scheme scheme: row.scheme
}); });
return ( return (

View File

@@ -1,16 +1,16 @@
export type SiteResourceDestinationInput = { export type SiteResourceDestinationInput = {
mode: "host" | "cidr" | "http"; mode: "host" | "cidr" | "http";
destination: string; destination: string;
httpHttpsPort: number | null; destinationPort: number | null;
scheme: "http" | "https" | null; scheme: "http" | "https" | null;
}; };
export function resolveHttpHttpsDisplayPort( export function resolveHttpHttpsDisplayPort(
mode: "http", mode: "http",
httpHttpsPort: number | null destinationPort: number | null
): number { ): number {
if (httpHttpsPort != null) { if (destinationPort != null) {
return httpHttpsPort; return destinationPort;
} }
return 80; return 80;
} }
@@ -18,11 +18,11 @@ export function resolveHttpHttpsDisplayPort(
export function formatSiteResourceDestinationDisplay( export function formatSiteResourceDestinationDisplay(
row: SiteResourceDestinationInput row: SiteResourceDestinationInput
): string { ): string {
const { mode, destination, httpHttpsPort, scheme } = row; const { mode, destination, destinationPort, scheme } = row;
if (mode !== "http") { if (mode !== "http") {
return destination; return destination;
} }
const port = resolveHttpHttpsDisplayPort(mode, httpHttpsPort); const port = resolveHttpHttpsDisplayPort(mode, destinationPort);
const downstreamScheme = scheme ?? "http"; const downstreamScheme = scheme ?? "http";
const hostPart = const hostPart =
destination.includes(":") && !destination.startsWith("[") destination.includes(":") && !destination.startsWith("[")