diff --git a/src/app/[orgId]/settings/sites/[niceId]/general/page.tsx b/src/app/[orgId]/settings/sites/[niceId]/general/page.tsx index 75406f48..50a1faff 100644 --- a/src/app/[orgId]/settings/sites/[niceId]/general/page.tsx +++ b/src/app/[orgId]/settings/sites/[niceId]/general/page.tsx @@ -15,7 +15,7 @@ import { import { Input } from "@/components/ui/input"; import { useSiteContext } from "@app/hooks/useSiteContext"; import { useForm } from "react-hook-form"; -import { toast } from "@app/hooks/useToast"; +import { toast, useToast } from "@app/hooks/useToast"; import { useRouter } from "next/navigation"; import { SettingsContainer, @@ -37,6 +37,7 @@ import { Tag, TagInput } from "@app/components/tags/tag-input"; const GeneralFormSchema = z.object({ name: z.string().nonempty("Name is required"), + niceId: z.string().optional(), dockerSocketEnabled: z.boolean().optional(), remoteSubnets: z .array( @@ -55,19 +56,18 @@ export default function GeneralPage() { const { env } = useEnvContext(); const api = createApiClient(useEnvContext()); - - const [loading, setLoading] = useState(false); - const [activeCidrTagIndex, setActiveCidrTagIndex] = useState( - null - ); - const router = useRouter(); const t = useTranslations(); + const { toast } = useToast(); + + const [loading, setLoading] = useState(false); + const [activeCidrTagIndex, setActiveCidrTagIndex] = useState(null); const form = useForm({ resolver: zodResolver(GeneralFormSchema), defaultValues: { name: site?.name, + niceId: site?.niceId || "", dockerSocketEnabled: site?.dockerSocketEnabled ?? false, remoteSubnets: site?.remoteSubnets ? site.remoteSubnets.split(",").map((subnet, index) => ({ @@ -82,37 +82,40 @@ export default function GeneralPage() { async function onSubmit(data: GeneralFormValues) { setLoading(true); - await api - .post(`/site/${site?.siteId}`, { + try { + await api.post(`/site/${site?.siteId}`, { name: data.name, + niceId: data.niceId, dockerSocketEnabled: data.dockerSocketEnabled, remoteSubnets: data.remoteSubnets - ?.map((subnet) => subnet.text) - .join(",") || "" - }) - .catch((e) => { - toast({ - variant: "destructive", - title: t("siteErrorUpdate"), - description: formatAxiosError( - e, - t("siteErrorUpdateDescription") - ) - }); + ?.map((subnet) => subnet.text) + .join(",") || "" }); - updateSite({ - name: data.name, - dockerSocketEnabled: data.dockerSocketEnabled, - remoteSubnets: - data.remoteSubnets?.map((subnet) => subnet.text).join(",") || "" - }); + updateSite({ + name: data.name, + niceId: data.niceId, + dockerSocketEnabled: data.dockerSocketEnabled, + remoteSubnets: + data.remoteSubnets?.map((subnet) => subnet.text).join(",") || "" + }); - toast({ - title: t("siteUpdated"), - description: t("siteUpdatedDescription") - }); + if (data.niceId && data.niceId !== site?.niceId) { + router.replace(`/${site?.orgId}/settings/sites/${data.niceId}/general`); + } + + toast({ + title: t("siteUpdated"), + description: t("siteUpdatedDescription") + }); + } catch (e) { + toast({ + variant: "destructive", + title: t("siteErrorUpdate"), + description: formatAxiosError(e, t("siteErrorUpdateDescription")) + }); + } setLoading(false); @@ -153,8 +156,25 @@ export default function GeneralPage() { )} /> - {env.flags.enableClients && - site.type === "newt" ? ( + ( + + {t("niceId") || "Nice ID"} + + + + + + )} + /> + + {env.flags.enableClients && site.type === "newt" ? ( { if (type === "newt") { @@ -46,130 +31,11 @@ export default function SiteInfoCard({ }: SiteInfoCardProps) { } }; - const handleEdit = () => { - setTempNiceId(niceId); - setIsEditing(true); - }; - - const handleCancel = () => { - setTempNiceId(niceId); - setIsEditing(false); - }; - - const handleSave = async () => { - if (tempNiceId.trim() === "") { - toast({ - variant: "destructive", - title: t("error"), - description: t("niceIdCannotBeEmpty") - }); - return; - } - - if (tempNiceId === niceId) { - setIsEditing(false); - return; - } - - setIsLoading(true); - - try { - const response = await api.post(`/site/${site.siteId}`, { - niceId: tempNiceId.trim() - }); - - setNiceId(tempNiceId.trim()); - setIsEditing(false); - - updateSite({ - niceId: tempNiceId.trim() - }); - - // update the URL to reflect the new niceId - const newPath = pathname.replace(`/sites/${niceId}`, `/sites/${tempNiceId.trim()}`); - router.replace(newPath); - - toast({ - title: t("niceIdUpdated"), - description: t("niceIdUpdatedSuccessfully") - }); - } catch (e: any) { - toast({ - variant: "destructive", - title: t("niceIdUpdateError"), - description: formatAxiosError( - e, - t("niceIdUpdateErrorDescription") - ) - }); - } finally { - setIsLoading(false); - } - }; - - const handleKeyDown = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - handleSave(); - } else if (e.key === "Escape") { - handleCancel(); - } - }; return ( - - - - {t("niceId")} - - -
- {isEditing ? ( - <> - setTempNiceId(e.target.value)} - onKeyDown={handleKeyDown} - disabled={isLoading} - className="flex-1" - autoFocus - /> - - - - ) : ( - <> - {niceId} - - - )} -
-
-
+ {(site.type == "newt" || site.type == "wireguard") && ( <>