mirror of
https://github.com/fosrl/pangolin.git
synced 2026-05-28 11:43:03 +00:00
Trying to get these forms to work
This commit is contained in:
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.scheme !== null &&
|
||||||
data.destinationPort !== undefined &&
|
data.destinationPort !== undefined &&
|
||||||
|
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:
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -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,7 +129,7 @@ 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 &&
|
||||||
@@ -135,6 +138,15 @@ const updateSiteResourceSchema = z
|
|||||||
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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,
|
||||||
|
|||||||
@@ -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,8 +821,69 @@ export function InternalResourceForm({
|
|||||||
<FormLabel>
|
<FormLabel>
|
||||||
{t("sites")}
|
{t("sites")}
|
||||||
</FormLabel>
|
</FormLabel>
|
||||||
|
{mode === "ssh" &&
|
||||||
|
sshServerMode ===
|
||||||
|
"native" ? (
|
||||||
<Popover>
|
<Popover>
|
||||||
<PopoverTrigger asChild>
|
<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">
|
||||||
|
{selectedSites[0]
|
||||||
|
?.name ??
|
||||||
|
t(
|
||||||
|
"selectSite"
|
||||||
|
)}
|
||||||
|
</span>
|
||||||
|
<ChevronsUpDown className="ml-2 h-4 w-4 shrink-0 opacity-50" />
|
||||||
|
</Button>
|
||||||
|
</FormControl>
|
||||||
|
</PopoverTrigger>
|
||||||
|
<PopoverContent className="w-full p-0">
|
||||||
|
<SitesSelector
|
||||||
|
orgId={
|
||||||
|
orgId
|
||||||
|
}
|
||||||
|
selectedSite={
|
||||||
|
selectedSites[0] ??
|
||||||
|
null
|
||||||
|
}
|
||||||
|
filterTypes={[
|
||||||
|
"newt"
|
||||||
|
]}
|
||||||
|
onSelectSite={(
|
||||||
|
site
|
||||||
|
) => {
|
||||||
|
setSelectedSites(
|
||||||
|
[
|
||||||
|
site
|
||||||
|
]
|
||||||
|
);
|
||||||
|
field.onChange(
|
||||||
|
[
|
||||||
|
site.siteId
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
</PopoverContent>
|
||||||
|
</Popover>
|
||||||
|
) : (
|
||||||
|
<Popover>
|
||||||
|
<PopoverTrigger
|
||||||
|
asChild
|
||||||
|
>
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<Button
|
<Button
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@@ -837,7 +907,9 @@ export function InternalResourceForm({
|
|||||||
</PopoverTrigger>
|
</PopoverTrigger>
|
||||||
<PopoverContent className="w-full p-0">
|
<PopoverContent className="w-full p-0">
|
||||||
<MultiSitesSelector
|
<MultiSitesSelector
|
||||||
orgId={orgId}
|
orgId={
|
||||||
|
orgId
|
||||||
|
}
|
||||||
selectedSites={
|
selectedSites={
|
||||||
selectedSites
|
selectedSites
|
||||||
}
|
}
|
||||||
@@ -862,6 +934,7 @@ export function InternalResourceForm({
|
|||||||
/>
|
/>
|
||||||
</PopoverContent>
|
</PopoverContent>
|
||||||
</Popover>
|
</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,8 +1109,9 @@ export function InternalResourceForm({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{(mode === "host" || mode === "ssh") &&
|
{(mode === "host" ||
|
||||||
sshServerMode !== "native" && (
|
(mode === "ssh" &&
|
||||||
|
sshServerMode !== "native")) && (
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
@@ -1057,16 +1137,18 @@ export function InternalResourceForm({
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{mode === "http" && (
|
{(mode === "http" ||
|
||||||
|
(mode === "ssh" &&
|
||||||
|
sshServerMode !== "native")) && (
|
||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<FormField
|
<FormField
|
||||||
control={form.control}
|
control={form.control}
|
||||||
name="httpHttpsPort"
|
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",
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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("[")
|
||||||
|
|||||||
Reference in New Issue
Block a user