Make sure the right type of select shows

This commit is contained in:
Owen
2026-06-02 16:33:05 -07:00
parent 19feaf4bf2
commit 8bcc130947
7 changed files with 75 additions and 38 deletions

View File

@@ -49,7 +49,6 @@ const createSiteResourceSchema = z
scheme: z.enum(["http", "https"]).optional(), scheme: z.enum(["http", "https"]).optional(),
siteIds: z.array(z.int()).optional(), siteIds: z.array(z.int()).optional(),
siteId: z.number().int().positive().optional(), // DEPRECATED: for backward compatibility, we will convert this to siteIds array if provided siteId: z.number().int().positive().optional(), // DEPRECATED: for backward compatibility, we will convert this to siteIds array if provided
// proxyPort: z.int().positive().optional(),
destinationPort: z.int().positive().optional(), destinationPort: z.int().positive().optional(),
destination: z.string().min(1).optional(), destination: z.string().min(1).optional(),
enabled: z.boolean().default(true), enabled: z.boolean().default(true),
@@ -248,7 +247,6 @@ export async function createSiteResource(
siteId, siteId,
mode, mode,
scheme, scheme,
// proxyPort,
destinationPort, destinationPort,
destination, destination,
enabled, enabled,

View File

@@ -59,7 +59,6 @@ const updateSiteResourceSchema = z
mode: z.enum(["host", "cidr", "http", "ssh"]).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(),
destinationPort: z.int().positive().nullish(), destinationPort: z.int().positive().nullish(),
destination: z.string().min(1).optional(), destination: z.string().min(1).optional(),
enabled: z.boolean().optional(), enabled: z.boolean().optional(),
@@ -632,6 +631,15 @@ 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({
@@ -644,9 +652,14 @@ export async function updateSiteResource(
destinationPort: destinationPort, destinationPort: destinationPort,
enabled: enabled, enabled: enabled,
alias: alias ? alias.trim() : null, alias: alias ? alias.trim() : null,
tcpPortRangeString: tcpPortRangeString, tcpPortRangeString: tcpPortRangeStringAdjusted,
udpPortRangeString: udpPortRangeString, udpPortRangeString:
disableIcmp: disableIcmp, mode == "http" || mode == "ssh"
? ""
: udpPortRangeString,
disableIcmp:
disableIcmp ||
(mode == "http" || mode == "ssh" ? true : false),
domainId, domainId,
subdomain: finalSubdomain, subdomain: finalSubdomain,
fullDomain, fullDomain,

View File

@@ -480,7 +480,8 @@ function SshServerForm({
/> />
</PopoverContent> </PopoverContent>
</Popover> </Popover>
) : standardDaemonLocation !== "site" ? ( ) : standardDaemonLocation !== "site" ||
pamMode === "passthrough" ? (
<BrowserGatewayTargetForm <BrowserGatewayTargetForm
orgId={orgId} orgId={orgId}
multiSite={true} multiSite={true}

View File

@@ -27,7 +27,6 @@ import {
StrategySelect, StrategySelect,
type StrategyOption type StrategyOption
} from "@app/components/StrategySelect"; } from "@app/components/StrategySelect";
import { ResourceTargetAddressItem } from "@app/components/resource-target-address-item";
import { BrowserGatewayTargetForm } from "@app/components/BrowserGatewayTargetForm"; import { BrowserGatewayTargetForm } from "@app/components/BrowserGatewayTargetForm";
import { import {
SitesSelector, SitesSelector,
@@ -896,26 +895,23 @@ export default function Page() {
/> />
</div> </div>
{/* Auth Method (standard only) */} <div className="space-y-3">
{!isNative && ( <p className="text-sm font-semibold">
<div className="space-y-3"> {t(
<p className="text-sm font-semibold"> "sshAuthenticationMethod"
{t( )}
"sshAuthenticationMethod" </p>
)} <StrategySelect<
</p> "passthrough" | "push"
<StrategySelect< >
"passthrough" | "push" value={pamMode}
> options={
value={pamMode} authMethodOptions
options={ }
authMethodOptions onChange={setPamMode}
} cols={2}
onChange={setPamMode} />
cols={2} </div>
/>
</div>
)}
{/* Daemon Location (standard + push) */} {/* Daemon Location (standard + push) */}
{showDaemonLocation && ( {showDaemonLocation && (
@@ -1046,7 +1042,9 @@ export default function Page() {
</PopoverContent> </PopoverContent>
</Popover> </Popover>
) : standardDaemonLocation !== ) : standardDaemonLocation !==
"site" ? ( "site" ||
pamMode ===
"passthrough" ? (
<BrowserGatewayTargetForm <BrowserGatewayTargetForm
orgId={orgId as string} orgId={orgId as string}
multiSite={true} multiSite={true}

View File

@@ -103,6 +103,7 @@ export default function CreatePrivateResourceDialog({
data.alias.trim() data.alias.trim()
? data.alias ? data.alias
: undefined, : undefined,
destinationPort: data.destinationPort ?? undefined,
pamMode: data.pamMode ?? undefined, pamMode: data.pamMode ?? undefined,
...(data.authDaemonMode != null && { ...(data.authDaemonMode != null && {
authDaemonMode: data.authDaemonMode authDaemonMode: data.authDaemonMode
@@ -112,13 +113,14 @@ export default function CreatePrivateResourceDialog({
authDaemonPort: data.authDaemonPort authDaemonPort: data.authDaemonPort
}) })
}), }),
...((data.mode === "host" || ...((data.mode === "host" || data.mode === "cidr") && {
data.mode === "ssh" ||
data.mode === "cidr") && {
tcpPortRangeString: data.tcpPortRangeString, tcpPortRangeString: data.tcpPortRangeString,
udpPortRangeString: data.udpPortRangeString, udpPortRangeString: data.udpPortRangeString,
disableIcmp: data.disableIcmp ?? false disableIcmp: data.disableIcmp ?? false
}), }),
...(data.mode === "ssh" && {
disableIcmp: data.disableIcmp ?? false
}),
roleIds: data.roles roleIds: data.roles
? data.roles.map((r) => parseInt(r.id)) ? data.roles.map((r) => parseInt(r.id))
: [], : [],

View File

@@ -104,6 +104,7 @@ export default function EditPrivateResourceDialog({
data.alias.trim() data.alias.trim()
? data.alias ? data.alias
: null, : null,
destinationPort: data.destinationPort ?? null,
pamMode: data.pamMode ?? undefined, pamMode: data.pamMode ?? undefined,
...(data.authDaemonMode != null && { ...(data.authDaemonMode != null && {
authDaemonMode: data.authDaemonMode authDaemonMode: data.authDaemonMode
@@ -112,13 +113,14 @@ export default function EditPrivateResourceDialog({
authDaemonPort: data.authDaemonPort || null authDaemonPort: data.authDaemonPort || null
}) })
}), }),
...((data.mode === "host" || ...((data.mode === "host" || data.mode === "cidr") && {
data.mode === "ssh" ||
data.mode === "cidr") && {
tcpPortRangeString: data.tcpPortRangeString, tcpPortRangeString: data.tcpPortRangeString,
udpPortRangeString: data.udpPortRangeString, udpPortRangeString: data.udpPortRangeString,
disableIcmp: data.disableIcmp ?? false disableIcmp: data.disableIcmp ?? false
}), }),
...(data.mode === "ssh" && {
disableIcmp: data.disableIcmp ?? false
}),
roleIds: (data.roles || []).map((r) => parseInt(r.id)), roleIds: (data.roles || []).map((r) => parseInt(r.id)),
userIds: (data.users || []).map((u) => u.id), userIds: (data.users || []).map((u) => u.id),
clientIds: (data.clients || []).map((c) => parseInt(c.id)) clientIds: (data.clients || []).map((c) => parseInt(c.id))

View File

@@ -365,6 +365,19 @@ export function PrivateResourceForm({
path: ["destination"] path: ["destination"]
}); });
} }
if (data.mode === "ssh" && !isNativeSsh) {
if (
data.destinationPort == null ||
!Number.isFinite(data.destinationPort) ||
data.destinationPort < 1
) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
message: t("internalResourceHttpPortRequired"),
path: ["destinationPort"]
});
}
}
if (data.mode !== "http") return; if (data.mode !== "http") return;
if (!data.scheme) { if (!data.scheme) {
ctx.addIssue({ ctx.addIssue({
@@ -548,7 +561,7 @@ export function PrivateResourceForm({
mode: "host", mode: "host",
destination: "", destination: "",
alias: null, alias: null,
destinationPort: null, destinationPort: 22,
scheme: "http", scheme: "http",
ssl: true, ssl: true,
httpConfigSubdomain: null, httpConfigSubdomain: null,
@@ -735,6 +748,7 @@ export function PrivateResourceForm({
onSubmit={form.handleSubmit((values) => { onSubmit={form.handleSubmit((values) => {
const siteIds = values.siteIds; const siteIds = values.siteIds;
const trimmedDestination = values.destination?.trim(); const trimmedDestination = values.destination?.trim();
const isSshMode = values.mode === "ssh";
onSubmit({ onSubmit({
...values, ...values,
siteIds, siteIds,
@@ -742,6 +756,12 @@ export function PrivateResourceForm({
trimmedDestination && trimmedDestination.length > 0 trimmedDestination && trimmedDestination.length > 0
? trimmedDestination ? trimmedDestination
: null, : null,
tcpPortRangeString: isSshMode
? undefined
: values.tcpPortRangeString,
udpPortRangeString: isSshMode
? undefined
: values.udpPortRangeString,
clients: (values.clients ?? []).map((c) => ({ clients: (values.clients ?? []).map((c) => ({
id: c.clientId.toString(), id: c.clientId.toString(),
text: c.name text: c.name
@@ -826,8 +846,11 @@ export function PrivateResourceForm({
{t("sites")} {t("sites")}
</FormLabel> </FormLabel>
{mode === "ssh" && {mode === "ssh" &&
sshServerMode === (sshServerMode ===
"native" ? ( "native" ||
(pamMode === "push" &&
authDaemonMode ===
"site")) ? (
<Popover> <Popover>
<PopoverTrigger <PopoverTrigger
asChild asChild