add new modes, port input, and domain picker

This commit is contained in:
miloschwartz
2026-04-09 17:49:22 -04:00
parent e4cbf088b4
commit d73796b92e
7 changed files with 495 additions and 264 deletions

View File

@@ -1817,6 +1817,8 @@
"editInternalResourceDialogModePort": "Port", "editInternalResourceDialogModePort": "Port",
"editInternalResourceDialogModeHost": "Host", "editInternalResourceDialogModeHost": "Host",
"editInternalResourceDialogModeCidr": "CIDR", "editInternalResourceDialogModeCidr": "CIDR",
"editInternalResourceDialogModeHttp": "HTTP",
"editInternalResourceDialogModeHttps": "HTTPS",
"editInternalResourceDialogDestination": "Destination", "editInternalResourceDialogDestination": "Destination",
"editInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.", "editInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.",
"editInternalResourceDialogDestinationIPDescription": "The IP or hostname address of the resource on the site's network.", "editInternalResourceDialogDestinationIPDescription": "The IP or hostname address of the resource on the site's network.",
@@ -1860,6 +1862,8 @@
"createInternalResourceDialogModePort": "Port", "createInternalResourceDialogModePort": "Port",
"createInternalResourceDialogModeHost": "Host", "createInternalResourceDialogModeHost": "Host",
"createInternalResourceDialogModeCidr": "CIDR", "createInternalResourceDialogModeCidr": "CIDR",
"createInternalResourceDialogModeHttp": "HTTP",
"createInternalResourceDialogModeHttps": "HTTPS",
"createInternalResourceDialogDestination": "Destination", "createInternalResourceDialogDestination": "Destination",
"createInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.", "createInternalResourceDialogDestinationHostDescription": "The IP address or hostname of the resource on the site's network.",
"createInternalResourceDialogDestinationCidrDescription": "The CIDR range of the resource on the site's network.", "createInternalResourceDialogDestinationCidrDescription": "The CIDR range of the resource on the site's network.",
@@ -2661,6 +2665,10 @@
"editInternalResourceDialogDestinationLabel": "Destination", "editInternalResourceDialogDestinationLabel": "Destination",
"editInternalResourceDialogDestinationDescription": "Specify the destination address for the internal resource. This can be a hostname, IP address, or CIDR range depending on the selected mode. Optionally set an internal DNS alias for easier identification.", "editInternalResourceDialogDestinationDescription": "Specify the destination address for the internal resource. This can be a hostname, IP address, or CIDR range depending on the selected mode. Optionally set an internal DNS alias for easier identification.",
"editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.", "editInternalResourceDialogPortRestrictionsDescription": "Restrict access to specific TCP/UDP ports or allow/block all ports.",
"createInternalResourceDialogHttpConfiguration": "HTTP configuration",
"createInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
"editInternalResourceDialogHttpConfiguration": "HTTP configuration",
"editInternalResourceDialogHttpConfigurationDescription": "Choose the domain clients will use to reach this resource over HTTP or HTTPS.",
"editInternalResourceDialogTcp": "TCP", "editInternalResourceDialogTcp": "TCP",
"editInternalResourceDialogUdp": "UDP", "editInternalResourceDialogUdp": "UDP",
"editInternalResourceDialogIcmp": "ICMP", "editInternalResourceDialogIcmp": "ICMP",

View File

@@ -36,7 +36,7 @@ const createSiteResourceParamsSchema = z.strictObject({
const createSiteResourceSchema = z const createSiteResourceSchema = z
.strictObject({ .strictObject({
name: z.string().min(1).max(255), name: z.string().min(1).max(255),
mode: z.enum(["host", "cidr", "port", "http", "https"]), mode: z.enum(["host", "cidr", "http", "https"]),
siteId: z.int(), siteId: z.int(),
// protocol: z.enum(["tcp", "udp"]).optional(), // protocol: z.enum(["tcp", "udp"]).optional(),
// proxyPort: z.int().positive().optional(), // proxyPort: z.int().positive().optional(),
@@ -286,8 +286,7 @@ export async function createSiteResource(
const niceId = await getUniqueSiteResourceName(orgId); const niceId = await getUniqueSiteResourceName(orgId);
let aliasAddress: string | null = null; let aliasAddress: string | null = null;
if (mode == "host") { if (mode === "host" || mode === "http" || mode === "https") {
// we can only have an alias on a host
aliasAddress = await getNextAvailableAliasAddress(orgId); aliasAddress = await getNextAvailableAliasAddress(orgId);
} }
@@ -299,7 +298,7 @@ export async function createSiteResource(
niceId, niceId,
orgId, orgId,
name, name,
mode: mode as "host" | "cidr", mode,
destination, destination,
destinationPort, destinationPort,
enabled, enabled,

View File

@@ -41,12 +41,12 @@ const listAllSiteResourcesByOrgQuerySchema = z.object({
}), }),
query: z.string().optional(), query: z.string().optional(),
mode: z mode: z
.enum(["host", "cidr"]) .enum(["host", "cidr", "http", "https"])
.optional() .optional()
.catch(undefined) .catch(undefined)
.openapi({ .openapi({
type: "string", type: "string",
enum: ["host", "cidr"], enum: ["host", "cidr", "http", "https"],
description: "Filter site resources by mode" description: "Filter site resources by mode"
}), }),
sort_by: z sort_by: z

View File

@@ -46,7 +46,7 @@ export type InternalResourceRow = {
siteName: string; siteName: string;
siteAddress: string | null; siteAddress: string | null;
// mode: "host" | "cidr" | "port"; // mode: "host" | "cidr" | "port";
mode: "host" | "cidr"; mode: "host" | "cidr" | "http" | "https";
// protocol: string | null; // protocol: string | null;
// proxyPort: number | null; // proxyPort: number | null;
siteId: number; siteId: number;
@@ -215,6 +215,14 @@ export default function ClientResourcesTable({
{ {
value: "cidr", value: "cidr",
label: t("editInternalResourceDialogModeCidr") label: t("editInternalResourceDialogModeCidr")
},
{
value: "http",
label: t("editInternalResourceDialogModeHttp")
},
{
value: "https",
label: t("editInternalResourceDialogModeHttps")
} }
]} ]}
selectedValue={searchParams.get("mode") ?? undefined} selectedValue={searchParams.get("mode") ?? undefined}
@@ -227,10 +235,15 @@ export default function ClientResourcesTable({
), ),
cell: ({ row }) => { cell: ({ row }) => {
const resourceRow = row.original; const resourceRow = row.original;
const modeLabels: Record<"host" | "cidr" | "port", string> = { const modeLabels: Record<
"host" | "cidr" | "port" | "http" | "https",
string
> = {
host: t("editInternalResourceDialogModeHost"), host: t("editInternalResourceDialogModeHost"),
cidr: t("editInternalResourceDialogModeCidr"), cidr: t("editInternalResourceDialogModeCidr"),
port: t("editInternalResourceDialogModePort") port: t("editInternalResourceDialogModePort"),
http: t("editInternalResourceDialogModeHttp"),
https: t("editInternalResourceDialogModeHttps")
}; };
return <span>{modeLabels[resourceRow.mode]}</span>; return <span>{modeLabels[resourceRow.mode]}</span>;
} }

View File

@@ -50,7 +50,12 @@ export default function CreateInternalResourceDialog({
setIsSubmitting(true); setIsSubmitting(true);
try { try {
let data = { ...values }; let data = { ...values };
if (data.mode === "host" && isHostname(data.destination)) { if (
(data.mode === "host" ||
data.mode === "http" ||
data.mode === "https") &&
isHostname(data.destination)
) {
const currentAlias = data.alias?.trim() || ""; const currentAlias = data.alias?.trim() || "";
if (!currentAlias) { if (!currentAlias) {
let aliasValue = data.destination; let aliasValue = data.destination;

View File

@@ -54,7 +54,12 @@ export default function EditInternalResourceDialog({
async function handleSubmit(values: InternalResourceFormValues) { async function handleSubmit(values: InternalResourceFormValues) {
try { try {
let data = { ...values }; let data = { ...values };
if (data.mode === "host" && isHostname(data.destination)) { if (
(data.mode === "host" ||
data.mode === "http" ||
data.mode === "https") &&
isHostname(data.destination)
) {
const currentAlias = data.alias?.trim() || ""; const currentAlias = data.alias?.trim() || "";
if (!currentAlias) { if (!currentAlias) {
let aliasValue = data.destination; let aliasValue = data.destination;

View File

@@ -45,6 +45,7 @@ import { z } from "zod";
import { SitesSelector, type Selectedsite } from "./site-selector"; import { SitesSelector, type Selectedsite } from "./site-selector";
import { CaretSortIcon } from "@radix-ui/react-icons"; import { CaretSortIcon } from "@radix-ui/react-icons";
import { MachinesSelector } from "./machines-selector"; import { MachinesSelector } from "./machines-selector";
import DomainPicker from "@app/components/DomainPicker";
// --- Helpers (shared) --- // --- Helpers (shared) ---
@@ -120,12 +121,14 @@ export const cleanForFQDN = (name: string): string =>
type Site = ListSitesResponse["sites"][0]; type Site = ListSitesResponse["sites"][0];
export type InternalResourceMode = "host" | "cidr" | "http" | "https";
export type InternalResourceData = { export type InternalResourceData = {
id: number; id: number;
name: string; name: string;
orgId: string; orgId: string;
siteName: string; siteName: string;
mode: "host" | "cidr"; mode: InternalResourceMode;
siteId: number; siteId: number;
niceId: string; niceId: string;
destination: string; destination: string;
@@ -135,6 +138,10 @@ export type InternalResourceData = {
disableIcmp?: boolean; disableIcmp?: boolean;
authDaemonMode?: "site" | "remote" | null; authDaemonMode?: "site" | "remote" | null;
authDaemonPort?: number | null; authDaemonPort?: number | null;
httpHttpsPort?: number | null;
httpConfigSubdomain?: string | null;
httpConfigDomainId?: string | null;
httpConfigFullDomain?: string | null;
}; };
const tagSchema = z.object({ id: z.string(), text: z.string() }); const tagSchema = z.object({ id: z.string(), text: z.string() });
@@ -142,7 +149,7 @@ const tagSchema = z.object({ id: z.string(), text: z.string() });
export type InternalResourceFormValues = { export type InternalResourceFormValues = {
name: string; name: string;
siteId: number; siteId: number;
mode: "host" | "cidr"; mode: InternalResourceMode;
destination: string; destination: string;
alias?: string | null; alias?: string | null;
niceId?: string; niceId?: string;
@@ -151,6 +158,10 @@ export type InternalResourceFormValues = {
disableIcmp?: boolean; disableIcmp?: boolean;
authDaemonMode?: "site" | "remote" | null; authDaemonMode?: "site" | "remote" | null;
authDaemonPort?: number | null; authDaemonPort?: number | null;
httpHttpsPort?: number | null;
httpConfigSubdomain?: string | null;
httpConfigDomainId?: string | null;
httpConfigFullDomain?: string | null;
roles?: z.infer<typeof tagSchema>[]; roles?: z.infer<typeof tagSchema>[];
users?: z.infer<typeof tagSchema>[]; users?: z.infer<typeof tagSchema>[];
clients?: z.infer<typeof tagSchema>[]; clients?: z.infer<typeof tagSchema>[];
@@ -211,6 +222,14 @@ export function InternalResourceForm({
variant === "create" variant === "create"
? "createInternalResourceDialogModeCidr" ? "createInternalResourceDialogModeCidr"
: "editInternalResourceDialogModeCidr"; : "editInternalResourceDialogModeCidr";
const modeHttpKey =
variant === "create"
? "createInternalResourceDialogModeHttp"
: "editInternalResourceDialogModeHttp";
const modeHttpsKey =
variant === "create"
? "createInternalResourceDialogModeHttps"
: "editInternalResourceDialogModeHttps";
const destinationLabelKey = const destinationLabelKey =
variant === "create" variant === "create"
? "createInternalResourceDialogDestination" ? "createInternalResourceDialogDestination"
@@ -223,6 +242,18 @@ export function InternalResourceForm({
variant === "create" variant === "create"
? "createInternalResourceDialogAlias" ? "createInternalResourceDialogAlias"
: "editInternalResourceDialogAlias"; : "editInternalResourceDialogAlias";
const httpHttpsPortLabelKey =
variant === "create"
? "createInternalResourceDialogModePort"
: "editInternalResourceDialogModePort";
const httpConfigurationTitleKey =
variant === "create"
? "createInternalResourceDialogHttpConfiguration"
: "editInternalResourceDialogHttpConfiguration";
const httpConfigurationDescriptionKey =
variant === "create"
? "createInternalResourceDialogHttpConfigurationDescription"
: "editInternalResourceDialogHttpConfigurationDescription";
const formSchema = z.object({ const formSchema = z.object({
name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)), name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)),
@@ -230,7 +261,7 @@ export function InternalResourceForm({
.number() .number()
.int() .int()
.positive(siteRequiredKey ? t(siteRequiredKey) : undefined), .positive(siteRequiredKey ? t(siteRequiredKey) : undefined),
mode: z.enum(["host", "cidr"]), mode: z.enum(["host", "cidr", "http", "https"]),
destination: z destination: z
.string() .string()
.min( .min(
@@ -240,6 +271,10 @@ export function InternalResourceForm({
: undefined : undefined
), ),
alias: z.string().nullish(), alias: z.string().nullish(),
httpHttpsPort: z.number().int().min(1).max(65535).optional().nullable(),
httpConfigSubdomain: z.string().nullish(),
httpConfigDomainId: z.string().nullish(),
httpConfigFullDomain: z.string().nullish(),
niceId: z niceId: z
.string() .string()
.min(1) .min(1)
@@ -394,6 +429,10 @@ export function InternalResourceForm({
disableIcmp: resource.disableIcmp ?? false, disableIcmp: resource.disableIcmp ?? false,
authDaemonMode: resource.authDaemonMode ?? "site", authDaemonMode: resource.authDaemonMode ?? "site",
authDaemonPort: resource.authDaemonPort ?? null, authDaemonPort: resource.authDaemonPort ?? null,
httpHttpsPort: resource.httpHttpsPort ?? null,
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
httpConfigDomainId: resource.httpConfigDomainId ?? null,
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
niceId: resource.niceId, niceId: resource.niceId,
roles: [], roles: [],
users: [], users: [],
@@ -405,6 +444,10 @@ export function InternalResourceForm({
mode: "host", mode: "host",
destination: "", destination: "",
alias: null, alias: null,
httpHttpsPort: null,
httpConfigSubdomain: null,
httpConfigDomainId: null,
httpConfigFullDomain: null,
tcpPortRangeString: "*", tcpPortRangeString: "*",
udpPortRangeString: "*", udpPortRangeString: "*",
disableIcmp: false, disableIcmp: false,
@@ -425,6 +468,10 @@ export function InternalResourceForm({
}); });
const mode = form.watch("mode"); const mode = form.watch("mode");
const httpConfigSubdomain = form.watch("httpConfigSubdomain");
const httpConfigDomainId = form.watch("httpConfigDomainId");
const httpConfigFullDomain = form.watch("httpConfigFullDomain");
const isHttpOrHttps = mode === "http" || mode === "https";
const authDaemonMode = form.watch("authDaemonMode") ?? "site"; const authDaemonMode = form.watch("authDaemonMode") ?? "site";
const hasInitialized = useRef(false); const hasInitialized = useRef(false);
const previousResourceId = useRef<number | null>(null); const previousResourceId = useRef<number | null>(null);
@@ -448,6 +495,10 @@ export function InternalResourceForm({
mode: "host", mode: "host",
destination: "", destination: "",
alias: null, alias: null,
httpHttpsPort: null,
httpConfigSubdomain: null,
httpConfigDomainId: null,
httpConfigFullDomain: null,
tcpPortRangeString: "*", tcpPortRangeString: "*",
udpPortRangeString: "*", udpPortRangeString: "*",
disableIcmp: false, disableIcmp: false,
@@ -475,6 +526,10 @@ 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,
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
httpConfigDomainId: resource.httpConfigDomainId ?? null,
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
tcpPortRangeString: resource.tcpPortRangeString ?? "*", tcpPortRangeString: resource.tcpPortRangeString ?? "*",
udpPortRangeString: resource.udpPortRangeString ?? "*", udpPortRangeString: resource.udpPortRangeString ?? "*",
disableIcmp: resource.disableIcmp ?? false, disableIcmp: resource.disableIcmp ?? false,
@@ -701,6 +756,12 @@ export function InternalResourceForm({
<SelectItem value="cidr"> <SelectItem value="cidr">
{t(modeCidrKey)} {t(modeCidrKey)}
</SelectItem> </SelectItem>
<SelectItem value="http">
{t(modeHttpKey)}
</SelectItem>
<SelectItem value="https">
{t(modeHttpsKey)}
</SelectItem>
</SelectContent> </SelectContent>
</Select> </Select>
<FormMessage /> <FormMessage />
@@ -731,7 +792,7 @@ export function InternalResourceForm({
)} )}
/> />
</div> </div>
{mode !== "cidr" && ( {mode === "host" && (
<div className="col-span-4"> <div className="col-span-4">
<FormField <FormField
control={form.control} control={form.control}
@@ -756,265 +817,405 @@ export function InternalResourceForm({
/> />
</div> </div>
)} )}
{(mode === "http" || mode === "https") && (
<div className="col-span-4">
<FormField
control={form.control}
name="httpHttpsPort"
render={({ field }) => (
<FormItem>
<FormLabel>
{t(
httpHttpsPortLabelKey
)}
</FormLabel>
<FormControl>
<Input
type="number"
min={1}
max={65535}
value={
field.value ??
""
}
onChange={(e) => {
const raw =
e.target
.value;
if (
raw === ""
) {
field.onChange(
null
);
return;
}
const n =
Number(raw);
field.onChange(
Number.isFinite(
n
)
? n
: null
);
}}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</div>
)}
</div> </div>
</div> </div>
<div className="space-y-4"> {isHttpOrHttps ? (
<div className="my-8"> <div className="space-y-4">
<label className="font-medium block"> <div className="my-8">
{t("portRestrictions")} <label className="font-medium block">
</label> {t(httpConfigurationTitleKey)}
<div className="text-sm text-muted-foreground"> </label>
{t( <div className="text-sm text-muted-foreground">
"editInternalResourceDialogPortRestrictionsDescription" {t(httpConfigurationDescriptionKey)}
</div>
</div>
<DomainPicker
key={
variant === "edit" && siteResourceId
? `http-domain-${siteResourceId}`
: "http-domain-create"
}
orgId={orgId}
cols={2}
hideFreeDomain
defaultSubdomain={
httpConfigSubdomain ?? undefined
}
defaultDomainId={
httpConfigDomainId ?? undefined
}
defaultFullDomain={
httpConfigFullDomain ?? undefined
}
onDomainChange={(res) => {
if (res === null) {
form.setValue(
"httpConfigSubdomain",
null
);
form.setValue(
"httpConfigDomainId",
null
);
form.setValue(
"httpConfigFullDomain",
null
);
return;
}
form.setValue(
"httpConfigSubdomain",
res.subdomain ?? null
);
form.setValue(
"httpConfigDomainId",
res.domainId
);
form.setValue(
"httpConfigFullDomain",
res.fullDomain
);
}}
/>
</div>
) : (
<div className="space-y-4">
<div className="my-8">
<label className="font-medium block">
{t("portRestrictions")}
</label>
<div className="text-sm text-muted-foreground">
{t(
"editInternalResourceDialogPortRestrictionsDescription"
)}
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)} )}
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)}
>
<div
className={
mode === "cidr"
? "col-span-1"
: "col-span-3"
}
> >
<FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70"> <div
{t("editInternalResourceDialogTcp")} className={
</FormLabel> mode === "cidr"
</div> ? "col-span-1"
<div : "col-span-3"
className={ }
mode === "cidr" >
? "col-span-3" <FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
: "col-span-9" {t("editInternalResourceDialogTcp")}
} </FormLabel>
> </div>
<FormField <div
control={form.control} className={
name="tcpPortRangeString" mode === "cidr"
render={() => ( ? "col-span-3"
<FormItem> : "col-span-9"
<div className="flex items-center gap-2"> }
<Select >
value={tcpPortMode} <FormField
onValueChange={( control={form.control}
v: PortMode name="tcpPortRangeString"
) => setTcpPortMode(v)} render={() => (
> <FormItem>
<FormControl> <div className="flex items-center gap-2">
<SelectTrigger className="w-[110px]"> <Select
<SelectValue /> value={tcpPortMode}
</SelectTrigger> onValueChange={(
</FormControl> v: PortMode
<SelectContent>
<SelectItem value="all">
{t("allPorts")}
</SelectItem>
<SelectItem value="blocked">
{t("blocked")}
</SelectItem>
<SelectItem value="custom">
{t("custom")}
</SelectItem>
</SelectContent>
</Select>
{tcpPortMode ===
"custom" ? (
<FormControl>
<Input
placeholder="80,443,8000-9000"
value={
tcpCustomPorts
}
onChange={(e) =>
setTcpCustomPorts(
e.target
.value
)
}
/>
</FormControl>
) : (
<Input
disabled
placeholder={
tcpPortMode ===
"all"
? t(
"allPortsAllowed"
)
: t(
"allPortsBlocked"
)
}
/>
)}
</div>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)}
>
<div
className={
mode === "cidr"
? "col-span-1"
: "col-span-3"
}
>
<FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{t("editInternalResourceDialogUdp")}
</FormLabel>
</div>
<div
className={
mode === "cidr"
? "col-span-3"
: "col-span-9"
}
>
<FormField
control={form.control}
name="udpPortRangeString"
render={() => (
<FormItem>
<div className="flex items-center gap-2">
<Select
value={udpPortMode}
onValueChange={(
v: PortMode
) => setUdpPortMode(v)}
>
<FormControl>
<SelectTrigger className="w-[110px]">
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="all">
{t("allPorts")}
</SelectItem>
<SelectItem value="blocked">
{t("blocked")}
</SelectItem>
<SelectItem value="custom">
{t("custom")}
</SelectItem>
</SelectContent>
</Select>
{udpPortMode ===
"custom" ? (
<FormControl>
<Input
placeholder="53,123,500-600"
value={
udpCustomPorts
}
onChange={(e) =>
setUdpCustomPorts(
e.target
.value
)
}
/>
</FormControl>
) : (
<Input
disabled
placeholder={
udpPortMode ===
"all"
? t(
"allPortsAllowed"
)
: t(
"allPortsBlocked"
)
}
/>
)}
</div>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)}
>
<div
className={
mode === "cidr"
? "col-span-1"
: "col-span-3"
}
>
<FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{t("editInternalResourceDialogIcmp")}
</FormLabel>
</div>
<div
className={
mode === "cidr"
? "col-span-3"
: "col-span-9"
}
>
<FormField
control={form.control}
name="disableIcmp"
render={({ field }) => (
<FormItem>
<div className="flex items-center gap-2">
<FormControl>
<Switch
checked={
!field.value
}
onCheckedChange={(
checked
) => ) =>
field.onChange( setTcpPortMode(
!checked v
) )
} }
/> >
</FormControl> <FormControl>
<span className="text-sm text-muted-foreground"> <SelectTrigger className="w-[110px]">
{field.value <SelectValue />
? t("blocked") </SelectTrigger>
: t("allowed")} </FormControl>
</span> <SelectContent>
</div> <SelectItem value="all">
<FormMessage /> {t(
</FormItem> "allPorts"
)} )}
/> </SelectItem>
<SelectItem value="blocked">
{t(
"blocked"
)}
</SelectItem>
<SelectItem value="custom">
{t(
"custom"
)}
</SelectItem>
</SelectContent>
</Select>
{tcpPortMode ===
"custom" ? (
<FormControl>
<Input
placeholder="80,443,8000-9000"
value={
tcpCustomPorts
}
onChange={(
e
) =>
setTcpCustomPorts(
e
.target
.value
)
}
/>
</FormControl>
) : (
<Input
disabled
placeholder={
tcpPortMode ===
"all"
? t(
"allPortsAllowed"
)
: t(
"allPortsBlocked"
)
}
/>
)}
</div>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)}
>
<div
className={
mode === "cidr"
? "col-span-1"
: "col-span-3"
}
>
<FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{t("editInternalResourceDialogUdp")}
</FormLabel>
</div>
<div
className={
mode === "cidr"
? "col-span-3"
: "col-span-9"
}
>
<FormField
control={form.control}
name="udpPortRangeString"
render={() => (
<FormItem>
<div className="flex items-center gap-2">
<Select
value={udpPortMode}
onValueChange={(
v: PortMode
) =>
setUdpPortMode(
v
)
}
>
<FormControl>
<SelectTrigger className="w-[110px]">
<SelectValue />
</SelectTrigger>
</FormControl>
<SelectContent>
<SelectItem value="all">
{t(
"allPorts"
)}
</SelectItem>
<SelectItem value="blocked">
{t(
"blocked"
)}
</SelectItem>
<SelectItem value="custom">
{t(
"custom"
)}
</SelectItem>
</SelectContent>
</Select>
{udpPortMode ===
"custom" ? (
<FormControl>
<Input
placeholder="53,123,500-600"
value={
udpCustomPorts
}
onChange={(
e
) =>
setUdpCustomPorts(
e
.target
.value
)
}
/>
</FormControl>
) : (
<Input
disabled
placeholder={
udpPortMode ===
"all"
? t(
"allPortsAllowed"
)
: t(
"allPortsBlocked"
)
}
/>
)}
</div>
<FormMessage />
</FormItem>
)}
/>
</div>
</div>
<div
className={cn(
"grid gap-4 items-start",
mode === "cidr"
? "grid-cols-4"
: "grid-cols-12"
)}
>
<div
className={
mode === "cidr"
? "col-span-1"
: "col-span-3"
}
>
<FormLabel className="text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70">
{t(
"editInternalResourceDialogIcmp"
)}
</FormLabel>
</div>
<div
className={
mode === "cidr"
? "col-span-3"
: "col-span-9"
}
>
<FormField
control={form.control}
name="disableIcmp"
render={({ field }) => (
<FormItem>
<div className="flex items-center gap-2">
<FormControl>
<Switch
checked={
!field.value
}
onCheckedChange={(
checked
) =>
field.onChange(
!checked
)
}
/>
</FormControl>
<span className="text-sm text-muted-foreground">
{field.value
? t("blocked")
: t("allowed")}
</span>
</div>
<FormMessage />
</FormItem>
)}
/>
</div>
</div> </div>
</div> </div>
</div> )}
</div> </div>
<div className="space-y-4 mt-4 p-1"> <div className="space-y-4 mt-4 p-1">