mirror of
https://github.com/fosrl/pangolin.git
synced 2026-04-11 04:16:38 +00:00
basic ui working
This commit is contained in:
@@ -46,7 +46,9 @@ export type InternalResourceRow = {
|
||||
siteName: string;
|
||||
siteAddress: string | null;
|
||||
// mode: "host" | "cidr" | "port";
|
||||
mode: "host" | "cidr" | "http" | "https";
|
||||
mode: "host" | "cidr" | "http";
|
||||
scheme: "http" | "https" | null;
|
||||
ssl: boolean;
|
||||
// protocol: string | null;
|
||||
// proxyPort: number | null;
|
||||
siteId: number;
|
||||
@@ -64,30 +66,27 @@ export type InternalResourceRow = {
|
||||
};
|
||||
|
||||
function resolveHttpHttpsDisplayPort(
|
||||
mode: "http" | "https",
|
||||
mode: "http",
|
||||
httpHttpsPort: number | null
|
||||
): number {
|
||||
if (httpHttpsPort != null) {
|
||||
return httpHttpsPort;
|
||||
}
|
||||
return mode === "https" ? 443 : 80;
|
||||
return 80;
|
||||
}
|
||||
|
||||
function formatDestinationDisplay(row: InternalResourceRow): string {
|
||||
const { mode, destination, httpHttpsPort } = row;
|
||||
if (mode !== "http" && mode !== "https") {
|
||||
const { mode, destination, httpHttpsPort, scheme } = row;
|
||||
if (mode !== "http") {
|
||||
return destination;
|
||||
}
|
||||
const port = resolveHttpHttpsDisplayPort(mode, httpHttpsPort);
|
||||
const downstreamScheme = scheme ?? "http";
|
||||
const hostPart =
|
||||
destination.includes(":") && !destination.startsWith("[")
|
||||
? `[${destination}]`
|
||||
: destination;
|
||||
return `${hostPart}:${port}`;
|
||||
}
|
||||
|
||||
function formatHttpHttpsAliasUrl(mode: "http" | "https", alias: string): string {
|
||||
return `${mode}://${alias}`;
|
||||
return `${downstreamScheme}://${hostPart}:${port}`;
|
||||
}
|
||||
|
||||
function isSafeUrlForLink(href: string): boolean {
|
||||
@@ -255,10 +254,6 @@ export default function ClientResourcesTable({
|
||||
{
|
||||
value: "http",
|
||||
label: t("editInternalResourceDialogModeHttp")
|
||||
},
|
||||
{
|
||||
value: "https",
|
||||
label: t("editInternalResourceDialogModeHttps")
|
||||
}
|
||||
]}
|
||||
selectedValue={searchParams.get("mode") ?? undefined}
|
||||
@@ -272,14 +267,13 @@ export default function ClientResourcesTable({
|
||||
cell: ({ row }) => {
|
||||
const resourceRow = row.original;
|
||||
const modeLabels: Record<
|
||||
"host" | "cidr" | "port" | "http" | "https",
|
||||
"host" | "cidr" | "port" | "http",
|
||||
string
|
||||
> = {
|
||||
host: t("editInternalResourceDialogModeHost"),
|
||||
cidr: t("editInternalResourceDialogModeCidr"),
|
||||
port: t("editInternalResourceDialogModePort"),
|
||||
http: t("editInternalResourceDialogModeHttp"),
|
||||
https: t("editInternalResourceDialogModeHttps")
|
||||
http: t("editInternalResourceDialogModeHttp")
|
||||
};
|
||||
return <span>{modeLabels[resourceRow.mode]}</span>;
|
||||
}
|
||||
@@ -319,15 +313,8 @@ export default function ClientResourcesTable({
|
||||
/>
|
||||
);
|
||||
}
|
||||
if (
|
||||
(resourceRow.mode === "http" ||
|
||||
resourceRow.mode === "https") &&
|
||||
resourceRow.alias
|
||||
) {
|
||||
const url = formatHttpHttpsAliasUrl(
|
||||
resourceRow.mode,
|
||||
resourceRow.alias
|
||||
);
|
||||
if (resourceRow.mode === "http" && resourceRow.alias) {
|
||||
const url = `${resourceRow.ssl ? "https" : "http"}://${resourceRow.alias}`;
|
||||
return (
|
||||
<CopyToClipboard
|
||||
text={url}
|
||||
|
||||
@@ -51,9 +51,7 @@ export default function CreateInternalResourceDialog({
|
||||
try {
|
||||
let data = { ...values };
|
||||
if (
|
||||
(data.mode === "host" ||
|
||||
data.mode === "http" ||
|
||||
data.mode === "https") &&
|
||||
(data.mode === "host" || data.mode === "http") &&
|
||||
isHostname(data.destination)
|
||||
) {
|
||||
const currentAlias = data.alias?.trim() || "";
|
||||
@@ -74,21 +72,42 @@ export default function CreateInternalResourceDialog({
|
||||
mode: data.mode,
|
||||
destination: data.destination,
|
||||
enabled: true,
|
||||
alias: data.alias && typeof data.alias === "string" && data.alias.trim() ? data.alias : undefined,
|
||||
...(data.mode === "http" && {
|
||||
scheme: data.scheme,
|
||||
ssl: data.ssl ?? false,
|
||||
destinationPort: data.httpHttpsPort ?? undefined
|
||||
}),
|
||||
alias:
|
||||
data.alias &&
|
||||
typeof data.alias === "string" &&
|
||||
data.alias.trim()
|
||||
? data.alias
|
||||
: undefined,
|
||||
tcpPortRangeString: data.tcpPortRangeString,
|
||||
udpPortRangeString: data.udpPortRangeString,
|
||||
disableIcmp: data.disableIcmp ?? false,
|
||||
...(data.authDaemonMode != null && { authDaemonMode: data.authDaemonMode }),
|
||||
...(data.authDaemonMode === "remote" && data.authDaemonPort != null && { authDaemonPort: data.authDaemonPort }),
|
||||
roleIds: data.roles ? data.roles.map((r) => parseInt(r.id)) : [],
|
||||
...(data.authDaemonMode != null && {
|
||||
authDaemonMode: data.authDaemonMode
|
||||
}),
|
||||
...(data.authDaemonMode === "remote" &&
|
||||
data.authDaemonPort != null && {
|
||||
authDaemonPort: data.authDaemonPort
|
||||
}),
|
||||
roleIds: data.roles
|
||||
? data.roles.map((r) => parseInt(r.id))
|
||||
: [],
|
||||
userIds: data.users ? data.users.map((u) => u.id) : [],
|
||||
clientIds: data.clients ? data.clients.map((c) => parseInt(c.id)) : []
|
||||
clientIds: data.clients
|
||||
? data.clients.map((c) => parseInt(c.id))
|
||||
: []
|
||||
}
|
||||
);
|
||||
|
||||
toast({
|
||||
title: t("createInternalResourceDialogSuccess"),
|
||||
description: t("createInternalResourceDialogInternalResourceCreatedSuccessfully"),
|
||||
description: t(
|
||||
"createInternalResourceDialogInternalResourceCreatedSuccessfully"
|
||||
),
|
||||
variant: "default"
|
||||
});
|
||||
setOpen(false);
|
||||
@@ -98,7 +117,9 @@ export default function CreateInternalResourceDialog({
|
||||
title: t("createInternalResourceDialogError"),
|
||||
description: formatAxiosError(
|
||||
error,
|
||||
t("createInternalResourceDialogFailedToCreateInternalResource")
|
||||
t(
|
||||
"createInternalResourceDialogFailedToCreateInternalResource"
|
||||
)
|
||||
),
|
||||
variant: "destructive"
|
||||
});
|
||||
@@ -111,9 +132,13 @@ export default function CreateInternalResourceDialog({
|
||||
<Credenza open={open} onOpenChange={setOpen}>
|
||||
<CredenzaContent className="max-w-3xl">
|
||||
<CredenzaHeader>
|
||||
<CredenzaTitle>{t("createInternalResourceDialogCreateClientResource")}</CredenzaTitle>
|
||||
<CredenzaTitle>
|
||||
{t("createInternalResourceDialogCreateClientResource")}
|
||||
</CredenzaTitle>
|
||||
<CredenzaDescription>
|
||||
{t("createInternalResourceDialogCreateClientResourceDescription")}
|
||||
{t(
|
||||
"createInternalResourceDialogCreateClientResourceDescription"
|
||||
)}
|
||||
</CredenzaDescription>
|
||||
</CredenzaHeader>
|
||||
<CredenzaBody>
|
||||
@@ -128,7 +153,11 @@ export default function CreateInternalResourceDialog({
|
||||
</CredenzaBody>
|
||||
<CredenzaFooter>
|
||||
<CredenzaClose asChild>
|
||||
<Button variant="outline" onClick={() => setOpen(false)} disabled={isSubmitting}>
|
||||
<Button
|
||||
variant="outline"
|
||||
onClick={() => setOpen(false)}
|
||||
disabled={isSubmitting}
|
||||
>
|
||||
{t("createInternalResourceDialogCancel")}
|
||||
</Button>
|
||||
</CredenzaClose>
|
||||
|
||||
@@ -55,9 +55,7 @@ export default function EditInternalResourceDialog({
|
||||
try {
|
||||
let data = { ...values };
|
||||
if (
|
||||
(data.mode === "host" ||
|
||||
data.mode === "http" ||
|
||||
data.mode === "https") &&
|
||||
(data.mode === "host" || data.mode === "http") &&
|
||||
isHostname(data.destination)
|
||||
) {
|
||||
const currentAlias = data.alias?.trim() || "";
|
||||
@@ -76,6 +74,11 @@ export default function EditInternalResourceDialog({
|
||||
mode: data.mode,
|
||||
niceId: data.niceId,
|
||||
destination: data.destination,
|
||||
...(data.mode === "http" && {
|
||||
scheme: data.scheme,
|
||||
ssl: data.ssl ?? false,
|
||||
destinationPort: data.httpHttpsPort ?? null
|
||||
}),
|
||||
alias:
|
||||
data.alias &&
|
||||
typeof data.alias === "string" &&
|
||||
|
||||
@@ -46,6 +46,7 @@ import { SitesSelector, type Selectedsite } from "./site-selector";
|
||||
import { CaretSortIcon } from "@radix-ui/react-icons";
|
||||
import { MachinesSelector } from "./machines-selector";
|
||||
import DomainPicker from "@app/components/DomainPicker";
|
||||
import { SwitchInput } from "@app/components/SwitchInput";
|
||||
|
||||
// --- Helpers (shared) ---
|
||||
|
||||
@@ -121,7 +122,7 @@ export const cleanForFQDN = (name: string): string =>
|
||||
|
||||
type Site = ListSitesResponse["sites"][0];
|
||||
|
||||
export type InternalResourceMode = "host" | "cidr" | "http" | "https";
|
||||
export type InternalResourceMode = "host" | "cidr" | "http";
|
||||
|
||||
export type InternalResourceData = {
|
||||
id: number;
|
||||
@@ -139,6 +140,8 @@ export type InternalResourceData = {
|
||||
authDaemonMode?: "site" | "remote" | null;
|
||||
authDaemonPort?: number | null;
|
||||
httpHttpsPort?: number | null;
|
||||
scheme?: "http" | "https" | null;
|
||||
ssl?: boolean;
|
||||
httpConfigSubdomain?: string | null;
|
||||
httpConfigDomainId?: string | null;
|
||||
httpConfigFullDomain?: string | null;
|
||||
@@ -159,6 +162,8 @@ export type InternalResourceFormValues = {
|
||||
authDaemonMode?: "site" | "remote" | null;
|
||||
authDaemonPort?: number | null;
|
||||
httpHttpsPort?: number | null;
|
||||
scheme?: "http" | "https";
|
||||
ssl?: boolean;
|
||||
httpConfigSubdomain?: string | null;
|
||||
httpConfigDomainId?: string | null;
|
||||
httpConfigFullDomain?: string | null;
|
||||
@@ -226,10 +231,18 @@ export function InternalResourceForm({
|
||||
variant === "create"
|
||||
? "createInternalResourceDialogModeHttp"
|
||||
: "editInternalResourceDialogModeHttp";
|
||||
const modeHttpsKey =
|
||||
const schemeLabelKey =
|
||||
variant === "create"
|
||||
? "createInternalResourceDialogModeHttps"
|
||||
: "editInternalResourceDialogModeHttps";
|
||||
? "createInternalResourceDialogScheme"
|
||||
: "editInternalResourceDialogScheme";
|
||||
const enableSslLabelKey =
|
||||
variant === "create"
|
||||
? "createInternalResourceDialogEnableSsl"
|
||||
: "editInternalResourceDialogEnableSsl";
|
||||
const enableSslDescriptionKey =
|
||||
variant === "create"
|
||||
? "createInternalResourceDialogEnableSslDescription"
|
||||
: "editInternalResourceDialogEnableSslDescription";
|
||||
const destinationLabelKey =
|
||||
variant === "create"
|
||||
? "createInternalResourceDialogDestination"
|
||||
@@ -255,48 +268,78 @@ export function InternalResourceForm({
|
||||
? "createInternalResourceDialogHttpConfigurationDescription"
|
||||
: "editInternalResourceDialogHttpConfigurationDescription";
|
||||
|
||||
const formSchema = z.object({
|
||||
name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)),
|
||||
siteId: z
|
||||
.number()
|
||||
.int()
|
||||
.positive(siteRequiredKey ? t(siteRequiredKey) : undefined),
|
||||
mode: z.enum(["host", "cidr", "http", "https"]),
|
||||
destination: z
|
||||
.string()
|
||||
.min(
|
||||
1,
|
||||
destinationRequiredKey
|
||||
? { message: t(destinationRequiredKey) }
|
||||
: undefined
|
||||
),
|
||||
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
|
||||
.string()
|
||||
.min(1)
|
||||
.max(255)
|
||||
.regex(/^[a-zA-Z0-9-]+$/)
|
||||
.optional(),
|
||||
tcpPortRangeString: createPortRangeStringSchema(t),
|
||||
udpPortRangeString: createPortRangeStringSchema(t),
|
||||
disableIcmp: z.boolean().optional(),
|
||||
authDaemonMode: z.enum(["site", "remote"]).optional().nullable(),
|
||||
authDaemonPort: z.number().int().positive().optional().nullable(),
|
||||
roles: z.array(tagSchema).optional(),
|
||||
users: z.array(tagSchema).optional(),
|
||||
clients: z
|
||||
.array(
|
||||
z.object({
|
||||
clientId: z.number(),
|
||||
name: z.string()
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
});
|
||||
const formSchema = z
|
||||
.object({
|
||||
name: z.string().min(1, t(nameRequiredKey)).max(255, t(nameMaxKey)),
|
||||
siteId: z
|
||||
.number()
|
||||
.int()
|
||||
.positive(siteRequiredKey ? t(siteRequiredKey) : undefined),
|
||||
mode: z.enum(["host", "cidr", "http"]),
|
||||
destination: z
|
||||
.string()
|
||||
.min(
|
||||
1,
|
||||
destinationRequiredKey
|
||||
? { message: t(destinationRequiredKey) }
|
||||
: undefined
|
||||
),
|
||||
alias: z.string().nullish(),
|
||||
httpHttpsPort: z
|
||||
.number()
|
||||
.int()
|
||||
.min(1)
|
||||
.max(65535)
|
||||
.optional()
|
||||
.nullable(),
|
||||
scheme: z.enum(["http", "https"]).optional(),
|
||||
ssl: z.boolean().optional(),
|
||||
httpConfigSubdomain: z.string().nullish(),
|
||||
httpConfigDomainId: z.string().nullish(),
|
||||
httpConfigFullDomain: z.string().nullish(),
|
||||
niceId: z
|
||||
.string()
|
||||
.min(1)
|
||||
.max(255)
|
||||
.regex(/^[a-zA-Z0-9-]+$/)
|
||||
.optional(),
|
||||
tcpPortRangeString: createPortRangeStringSchema(t),
|
||||
udpPortRangeString: createPortRangeStringSchema(t),
|
||||
disableIcmp: z.boolean().optional(),
|
||||
authDaemonMode: z.enum(["site", "remote"]).optional().nullable(),
|
||||
authDaemonPort: z.number().int().positive().optional().nullable(),
|
||||
roles: z.array(tagSchema).optional(),
|
||||
users: z.array(tagSchema).optional(),
|
||||
clients: z
|
||||
.array(
|
||||
z.object({
|
||||
clientId: z.number(),
|
||||
name: z.string()
|
||||
})
|
||||
)
|
||||
.optional()
|
||||
})
|
||||
.superRefine((data, ctx) => {
|
||||
if (data.mode !== "http") return;
|
||||
if (!data.scheme) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("internalResourceDownstreamSchemeRequired"),
|
||||
path: ["scheme"]
|
||||
});
|
||||
}
|
||||
if (
|
||||
data.httpHttpsPort == null ||
|
||||
!Number.isFinite(data.httpHttpsPort) ||
|
||||
data.httpHttpsPort < 1
|
||||
) {
|
||||
ctx.addIssue({
|
||||
code: z.ZodIssueCode.custom,
|
||||
message: t("internalResourceHttpPortRequired"),
|
||||
path: ["httpHttpsPort"]
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
type FormData = z.infer<typeof formSchema>;
|
||||
|
||||
@@ -430,6 +473,8 @@ export function InternalResourceForm({
|
||||
authDaemonMode: resource.authDaemonMode ?? "site",
|
||||
authDaemonPort: resource.authDaemonPort ?? null,
|
||||
httpHttpsPort: resource.httpHttpsPort ?? null,
|
||||
scheme: resource.scheme ?? "http",
|
||||
ssl: resource.ssl ?? false,
|
||||
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
|
||||
httpConfigDomainId: resource.httpConfigDomainId ?? null,
|
||||
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
|
||||
@@ -445,6 +490,8 @@ export function InternalResourceForm({
|
||||
destination: "",
|
||||
alias: null,
|
||||
httpHttpsPort: null,
|
||||
scheme: "http",
|
||||
ssl: false,
|
||||
httpConfigSubdomain: null,
|
||||
httpConfigDomainId: null,
|
||||
httpConfigFullDomain: null,
|
||||
@@ -471,7 +518,7 @@ export function InternalResourceForm({
|
||||
const httpConfigSubdomain = form.watch("httpConfigSubdomain");
|
||||
const httpConfigDomainId = form.watch("httpConfigDomainId");
|
||||
const httpConfigFullDomain = form.watch("httpConfigFullDomain");
|
||||
const isHttpOrHttps = mode === "http" || mode === "https";
|
||||
const isHttpMode = mode === "http";
|
||||
const authDaemonMode = form.watch("authDaemonMode") ?? "site";
|
||||
const hasInitialized = useRef(false);
|
||||
const previousResourceId = useRef<number | null>(null);
|
||||
@@ -496,6 +543,8 @@ export function InternalResourceForm({
|
||||
destination: "",
|
||||
alias: null,
|
||||
httpHttpsPort: null,
|
||||
scheme: "http",
|
||||
ssl: false,
|
||||
httpConfigSubdomain: null,
|
||||
httpConfigDomainId: null,
|
||||
httpConfigFullDomain: null,
|
||||
@@ -527,6 +576,8 @@ export function InternalResourceForm({
|
||||
destination: resource.destination ?? "",
|
||||
alias: resource.alias ?? null,
|
||||
httpHttpsPort: resource.httpHttpsPort ?? null,
|
||||
scheme: resource.scheme ?? "http",
|
||||
ssl: resource.ssl ?? false,
|
||||
httpConfigSubdomain: resource.httpConfigSubdomain ?? null,
|
||||
httpConfigDomainId: resource.httpConfigDomainId ?? null,
|
||||
httpConfigFullDomain: resource.httpConfigFullDomain ?? null,
|
||||
@@ -681,6 +732,37 @@ export function InternalResourceForm({
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="mode"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>{t(modeLabelKey)}</FormLabel>
|
||||
<Select
|
||||
onValueChange={field.onChange}
|
||||
value={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="host">
|
||||
{t(modeHostKey)}
|
||||
</SelectItem>
|
||||
<SelectItem value="cidr">
|
||||
{t(modeCidrKey)}
|
||||
</SelectItem>
|
||||
<SelectItem value="http">
|
||||
{t(modeHttpKey)}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
|
||||
<HorizontalTabs
|
||||
@@ -718,63 +800,56 @@ export function InternalResourceForm({
|
||||
<div
|
||||
className={cn(
|
||||
"grid gap-4 items-start",
|
||||
mode === "cidr"
|
||||
? "grid-cols-4"
|
||||
: "grid-cols-12"
|
||||
mode === "cidr" && "grid-cols-1",
|
||||
mode === "http" && "grid-cols-3",
|
||||
mode === "host" && "grid-cols-2"
|
||||
)}
|
||||
>
|
||||
{mode === "http" && (
|
||||
<div className="min-w-0">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="scheme"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(schemeLabelKey)}
|
||||
</FormLabel>
|
||||
<Select
|
||||
onValueChange={
|
||||
field.onChange
|
||||
}
|
||||
value={
|
||||
field.value ??
|
||||
"http"
|
||||
}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger className="w-full">
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="http">
|
||||
http
|
||||
</SelectItem>
|
||||
<SelectItem value="https">
|
||||
https
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={
|
||||
mode === "cidr"
|
||||
? "col-span-1"
|
||||
: "col-span-3"
|
||||
}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="mode"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormLabel>
|
||||
{t(modeLabelKey)}
|
||||
</FormLabel>
|
||||
<Select
|
||||
onValueChange={
|
||||
field.onChange
|
||||
}
|
||||
value={field.value}
|
||||
>
|
||||
<FormControl>
|
||||
<SelectTrigger>
|
||||
<SelectValue />
|
||||
</SelectTrigger>
|
||||
</FormControl>
|
||||
<SelectContent>
|
||||
<SelectItem value="host">
|
||||
{t(modeHostKey)}
|
||||
</SelectItem>
|
||||
<SelectItem value="cidr">
|
||||
{t(modeCidrKey)}
|
||||
</SelectItem>
|
||||
<SelectItem value="http">
|
||||
{t(modeHttpKey)}
|
||||
</SelectItem>
|
||||
<SelectItem value="https">
|
||||
{t(modeHttpsKey)}
|
||||
</SelectItem>
|
||||
</SelectContent>
|
||||
</Select>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
mode === "cidr"
|
||||
? "col-span-3"
|
||||
: "col-span-5"
|
||||
}
|
||||
className={cn(
|
||||
mode === "cidr" && "col-span-1",
|
||||
(mode === "http" || mode === "host") &&
|
||||
"min-w-0"
|
||||
)}
|
||||
>
|
||||
<FormField
|
||||
control={form.control}
|
||||
@@ -785,7 +860,7 @@ export function InternalResourceForm({
|
||||
{t(destinationLabelKey)}
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input {...field} />
|
||||
<Input {...field} className="w-full" />
|
||||
</FormControl>
|
||||
<FormMessage />
|
||||
</FormItem>
|
||||
@@ -793,7 +868,7 @@ export function InternalResourceForm({
|
||||
/>
|
||||
</div>
|
||||
{mode === "host" && (
|
||||
<div className="col-span-4">
|
||||
<div className="min-w-0">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="alias"
|
||||
@@ -805,6 +880,7 @@ export function InternalResourceForm({
|
||||
<FormControl>
|
||||
<Input
|
||||
{...field}
|
||||
className="w-full"
|
||||
value={
|
||||
field.value ??
|
||||
""
|
||||
@@ -817,8 +893,8 @@ export function InternalResourceForm({
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
{(mode === "http" || mode === "https") && (
|
||||
<div className="col-span-4">
|
||||
{mode === "http" && (
|
||||
<div className="min-w-0">
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="httpHttpsPort"
|
||||
@@ -831,6 +907,7 @@ export function InternalResourceForm({
|
||||
</FormLabel>
|
||||
<FormControl>
|
||||
<Input
|
||||
className="w-full"
|
||||
type="number"
|
||||
min={1}
|
||||
max={65535}
|
||||
@@ -842,16 +919,16 @@ export function InternalResourceForm({
|
||||
const raw =
|
||||
e.target
|
||||
.value;
|
||||
if (
|
||||
raw === ""
|
||||
) {
|
||||
if (raw === "") {
|
||||
field.onChange(
|
||||
null
|
||||
);
|
||||
return;
|
||||
}
|
||||
const n =
|
||||
Number(raw);
|
||||
Number(
|
||||
raw
|
||||
);
|
||||
field.onChange(
|
||||
Number.isFinite(
|
||||
n
|
||||
@@ -871,7 +948,7 @@ export function InternalResourceForm({
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{isHttpOrHttps ? (
|
||||
{isHttpMode ? (
|
||||
<div className="space-y-4">
|
||||
<div className="my-8">
|
||||
<label className="font-medium block">
|
||||
@@ -881,6 +958,29 @@ export function InternalResourceForm({
|
||||
{t(httpConfigurationDescriptionKey)}
|
||||
</div>
|
||||
</div>
|
||||
<FormField
|
||||
control={form.control}
|
||||
name="ssl"
|
||||
render={({ field }) => (
|
||||
<FormItem>
|
||||
<FormControl>
|
||||
<SwitchInput
|
||||
id="internal-resource-ssl"
|
||||
label={t(
|
||||
enableSslLabelKey
|
||||
)}
|
||||
description={t(
|
||||
enableSslDescriptionKey
|
||||
)}
|
||||
checked={!!field.value}
|
||||
onCheckedChange={
|
||||
field.onChange
|
||||
}
|
||||
/>
|
||||
</FormControl>
|
||||
</FormItem>
|
||||
)}
|
||||
/>
|
||||
<DomainPicker
|
||||
key={
|
||||
variant === "edit" && siteResourceId
|
||||
@@ -913,6 +1013,7 @@ export function InternalResourceForm({
|
||||
"httpConfigFullDomain",
|
||||
null
|
||||
);
|
||||
form.setValue("alias", null);
|
||||
return;
|
||||
}
|
||||
form.setValue(
|
||||
@@ -927,6 +1028,7 @@ export function InternalResourceForm({
|
||||
"httpConfigFullDomain",
|
||||
res.fullDomain
|
||||
);
|
||||
form.setValue("alias", res.fullDomain);
|
||||
}}
|
||||
/>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user