From 573747c237572864b622e4b427ba08d893760174 Mon Sep 17 00:00:00 2001 From: Owen Date: Fri, 31 Jul 2026 17:47:45 -0400 Subject: [PATCH] Add basic page to configure the alias --- messages/en-US.json | 1 + .../private/[niceId]/inference/page.tsx | 107 ++++++++++++++++++ .../resources/private/[niceId]/layout.tsx | 3 +- .../PrivateResourceDestinationFields.tsx | 31 +++++ src/lib/privateResourceForm.ts | 10 ++ 5 files changed, 151 insertions(+), 1 deletion(-) create mode 100644 src/app/[orgId]/settings/resources/private/[niceId]/inference/page.tsx diff --git a/messages/en-US.json b/messages/en-US.json index fd28a5469..94dd49f96 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -2256,6 +2256,7 @@ "requireDeviceApproval": "Require Device Approvals", "requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.", "sshSettings": "SSH Settings", + "inferenceSettings": "Inference Settings", "sshAccess": "SSH Access", "rdpSettings": "RDP Settings", "vncSettings": "VNC Settings", diff --git a/src/app/[orgId]/settings/resources/private/[niceId]/inference/page.tsx b/src/app/[orgId]/settings/resources/private/[niceId]/inference/page.tsx new file mode 100644 index 000000000..3f27f1172 --- /dev/null +++ b/src/app/[orgId]/settings/resources/private/[niceId]/inference/page.tsx @@ -0,0 +1,107 @@ +"use client"; + +import { + SettingsContainer, + SettingsFormCell, + SettingsFormGrid, + SettingsSection, + SettingsSectionBody, + SettingsSectionDescription, + SettingsSectionFooter, + SettingsSectionForm, + SettingsSectionHeader, + SettingsSectionTitle +} from "@app/components/Settings"; +import { Button } from "@app/components/ui/button"; +import { Form } from "@app/components/ui/form"; +import { createInferenceFormSchema } from "@app/lib/privateResourceForm"; +import { zodResolver } from "@hookform/resolvers/zod"; +import { useTranslations } from "next-intl"; +import { useActionState, useMemo, useState } from "react"; +import { useForm } from "react-hook-form"; +import { z } from "zod"; +import { PrivateResourceSitesField } from "@app/components/PrivateResourceSitesField"; +import { PrivateResourceInferenceDestinationFields } from "@app/components/PrivateResourceDestinationFields"; +import { PrivateResourcePortRanges } from "@app/components/PrivateResourcePortRanges"; +import { useSaveSiteResource } from "@app/hooks/useSaveSiteResource"; +import { + asAnyControl, + asAnySetValue, + asAnyWatch +} from "@app/lib/formControlUtils"; +import { buildSelectedSitesForResource } from "@app/lib/privateResourceUtils"; + +export default function PrivateResourceInferencePage() { + const t = useTranslations(); + const { save, siteResource } = useSaveSiteResource(); + const [selectedSites, setSelectedSites] = useState(() => + buildSelectedSitesForResource(siteResource) + ); + + const formSchema = useMemo(() => createInferenceFormSchema(t), [t]); + type FormValues = z.infer; + + const form = useForm({ + resolver: zodResolver(formSchema), + defaultValues: { + mode: "inference", + alias: siteResource.alias ?? null + } + }); + + const [, formAction, saveLoading] = useActionState(async () => { + const isValid = await form.trigger(); + if (!isValid) return; + + const data = form.getValues(); + await save({ + mode: "inference", + alias: data.alias + }); + }, null); + + return ( + + + + + {t("hostSettings")} + + + {t("editInternalResourceDialogDestinationDescription")} + + + + + +
+ + + + + + +
+ +
+
+ + + + +
+
+ ); +} diff --git a/src/app/[orgId]/settings/resources/private/[niceId]/layout.tsx b/src/app/[orgId]/settings/resources/private/[niceId]/layout.tsx index a1e97e188..f07b92673 100644 --- a/src/app/[orgId]/settings/resources/private/[niceId]/layout.tsx +++ b/src/app/[orgId]/settings/resources/private/[niceId]/layout.tsx @@ -52,7 +52,8 @@ export default async function PrivateResourceLayout( | "hostSettings" | "cidrSettings" | "httpSettings" - | "sshSettings"; + | "sshSettings" + | "inferenceSettings"; const navItems = [ { diff --git a/src/components/PrivateResourceDestinationFields.tsx b/src/components/PrivateResourceDestinationFields.tsx index 642ee0a5b..a10ce3161 100644 --- a/src/components/PrivateResourceDestinationFields.tsx +++ b/src/components/PrivateResourceDestinationFields.tsx @@ -76,6 +76,37 @@ type PrivateResourceHostDestinationFieldsProps = { hideAlias?: boolean; }; +type PrivateResourceInferenceDestinationFieldsProps = { + control: Control; + watch: UseFormWatch; + labelPrefix?: "create" | "edit"; + hideAlias?: boolean; +}; + +export function PrivateResourceInferenceDestinationFields({ + control, + watch, + labelPrefix = "edit" +}: PrivateResourceInferenceDestinationFieldsProps) { + const t = useTranslations(); + const destinationLabelKey = + labelPrefix === "create" + ? "createInternalResourceDialogDestination" + : "editInternalResourceDialogDestination"; + + return ( + + + + + + ); +} + export function PrivateResourceHostDestinationFields({ control, watch, diff --git a/src/lib/privateResourceForm.ts b/src/lib/privateResourceForm.ts index 844ff96cb..f2ff103f6 100644 --- a/src/lib/privateResourceForm.ts +++ b/src/lib/privateResourceForm.ts @@ -485,6 +485,7 @@ function destinationRefine( const isNativeSsh = data.mode === "ssh" && data.authDaemonMode === "native"; const trimmedDestination = data.destination?.trim(); if ( + data.mode !== "inference" && !isNativeSsh && (!trimmedDestination || trimmedDestination.length < 1) ) { @@ -555,6 +556,15 @@ export function createHostFormSchema(t: TranslateFn) { .superRefine((data, ctx) => destinationRefine(data, ctx, t)); } +export function createInferenceFormSchema(t: TranslateFn) { + return z + .object({ + mode: z.literal("inference"), + alias: z.string().nullish() + }) + .superRefine((data, ctx) => destinationRefine(data, ctx, t)); +} + export function createCidrFormSchema(t: TranslateFn) { return z .object({