mirror of
https://github.com/fosrl/pangolin.git
synced 2026-08-11 15:08:36 +02:00
Add basic page to configure the alias
This commit is contained in:
@@ -2256,6 +2256,7 @@
|
|||||||
"requireDeviceApproval": "Require Device Approvals",
|
"requireDeviceApproval": "Require Device Approvals",
|
||||||
"requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
|
"requireDeviceApprovalDescription": "Users with this role need new devices approved by an admin before they can connect and access resources.",
|
||||||
"sshSettings": "SSH Settings",
|
"sshSettings": "SSH Settings",
|
||||||
|
"inferenceSettings": "Inference Settings",
|
||||||
"sshAccess": "SSH Access",
|
"sshAccess": "SSH Access",
|
||||||
"rdpSettings": "RDP Settings",
|
"rdpSettings": "RDP Settings",
|
||||||
"vncSettings": "VNC Settings",
|
"vncSettings": "VNC Settings",
|
||||||
|
|||||||
@@ -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<typeof formSchema>;
|
||||||
|
|
||||||
|
const form = useForm<FormValues>({
|
||||||
|
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 (
|
||||||
|
<SettingsContainer>
|
||||||
|
<SettingsSection>
|
||||||
|
<SettingsSectionHeader>
|
||||||
|
<SettingsSectionTitle>
|
||||||
|
{t("hostSettings")}
|
||||||
|
</SettingsSectionTitle>
|
||||||
|
<SettingsSectionDescription>
|
||||||
|
{t("editInternalResourceDialogDestinationDescription")}
|
||||||
|
</SettingsSectionDescription>
|
||||||
|
</SettingsSectionHeader>
|
||||||
|
|
||||||
|
<SettingsSectionBody>
|
||||||
|
<SettingsSectionForm variant="half">
|
||||||
|
<Form {...form}>
|
||||||
|
<form
|
||||||
|
action={formAction}
|
||||||
|
id="private-resource-host-form"
|
||||||
|
>
|
||||||
|
<SettingsFormGrid>
|
||||||
|
<SettingsFormCell span="full">
|
||||||
|
<PrivateResourceInferenceDestinationFields
|
||||||
|
control={asAnyControl(form.control)}
|
||||||
|
watch={asAnyWatch(form.watch)}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
</SettingsFormGrid>
|
||||||
|
</form>
|
||||||
|
</Form>
|
||||||
|
</SettingsSectionForm>
|
||||||
|
</SettingsSectionBody>
|
||||||
|
|
||||||
|
<SettingsSectionFooter>
|
||||||
|
<Button
|
||||||
|
type="submit"
|
||||||
|
form="private-resource-host-form"
|
||||||
|
loading={saveLoading}
|
||||||
|
>
|
||||||
|
{t("saveSettings")}
|
||||||
|
</Button>
|
||||||
|
</SettingsSectionFooter>
|
||||||
|
</SettingsSection>
|
||||||
|
</SettingsContainer>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -52,7 +52,8 @@ export default async function PrivateResourceLayout(
|
|||||||
| "hostSettings"
|
| "hostSettings"
|
||||||
| "cidrSettings"
|
| "cidrSettings"
|
||||||
| "httpSettings"
|
| "httpSettings"
|
||||||
| "sshSettings";
|
| "sshSettings"
|
||||||
|
| "inferenceSettings";
|
||||||
|
|
||||||
const navItems = [
|
const navItems = [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -76,6 +76,37 @@ type PrivateResourceHostDestinationFieldsProps = {
|
|||||||
hideAlias?: boolean;
|
hideAlias?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
type PrivateResourceInferenceDestinationFieldsProps = {
|
||||||
|
control: Control<any>;
|
||||||
|
watch: UseFormWatch<any>;
|
||||||
|
labelPrefix?: "create" | "edit";
|
||||||
|
hideAlias?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
|
export function PrivateResourceInferenceDestinationFields({
|
||||||
|
control,
|
||||||
|
watch,
|
||||||
|
labelPrefix = "edit"
|
||||||
|
}: PrivateResourceInferenceDestinationFieldsProps) {
|
||||||
|
const t = useTranslations();
|
||||||
|
const destinationLabelKey =
|
||||||
|
labelPrefix === "create"
|
||||||
|
? "createInternalResourceDialogDestination"
|
||||||
|
: "editInternalResourceDialogDestination";
|
||||||
|
|
||||||
|
return (
|
||||||
|
<SettingsFormGrid>
|
||||||
|
<SettingsFormCell span="half">
|
||||||
|
<PrivateResourceAliasField
|
||||||
|
control={control}
|
||||||
|
watch={watch}
|
||||||
|
labelPrefix={labelPrefix}
|
||||||
|
/>
|
||||||
|
</SettingsFormCell>
|
||||||
|
</SettingsFormGrid>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export function PrivateResourceHostDestinationFields({
|
export function PrivateResourceHostDestinationFields({
|
||||||
control,
|
control,
|
||||||
watch,
|
watch,
|
||||||
|
|||||||
@@ -485,6 +485,7 @@ function destinationRefine(
|
|||||||
const isNativeSsh = data.mode === "ssh" && data.authDaemonMode === "native";
|
const isNativeSsh = data.mode === "ssh" && data.authDaemonMode === "native";
|
||||||
const trimmedDestination = data.destination?.trim();
|
const trimmedDestination = data.destination?.trim();
|
||||||
if (
|
if (
|
||||||
|
data.mode !== "inference" &&
|
||||||
!isNativeSsh &&
|
!isNativeSsh &&
|
||||||
(!trimmedDestination || trimmedDestination.length < 1)
|
(!trimmedDestination || trimmedDestination.length < 1)
|
||||||
) {
|
) {
|
||||||
@@ -555,6 +556,15 @@ export function createHostFormSchema(t: TranslateFn) {
|
|||||||
.superRefine((data, ctx) => destinationRefine(data, ctx, t));
|
.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) {
|
export function createCidrFormSchema(t: TranslateFn) {
|
||||||
return z
|
return z
|
||||||
.object({
|
.object({
|
||||||
|
|||||||
Reference in New Issue
Block a user