diff --git a/cli/commands/generateOrgCaKeys.ts b/cli/commands/generateOrgCaKeys.ts index fe38e0c56..ea12d8c3e 100644 --- a/cli/commands/generateOrgCaKeys.ts +++ b/cli/commands/generateOrgCaKeys.ts @@ -5,7 +5,7 @@ import { encrypt } from "@server/lib/crypto"; import { configFilePath1, configFilePath2 } from "@server/lib/consts"; import { generateCA } from "@server/lib/sshCA"; import fs from "fs"; -import yaml from "js-yaml"; +import * as yaml from "js-yaml"; type GenerateOrgCaKeysArgs = { orgId: string; diff --git a/cli/commands/rotateServerSecret.ts b/cli/commands/rotateServerSecret.ts index 1bacfa99c..8b26f4720 100644 --- a/cli/commands/rotateServerSecret.ts +++ b/cli/commands/rotateServerSecret.ts @@ -4,7 +4,7 @@ import { encrypt, decrypt } from "@server/lib/crypto"; import { configFilePath1, configFilePath2 } from "@server/lib/consts"; import { eq } from "drizzle-orm"; import fs from "fs"; -import yaml from "js-yaml"; +import * as yaml from "js-yaml"; type RotateServerSecretArgs = { "old-secret": string; diff --git a/public/screenshots/hero.png b/public/screenshots/hero.png index 46ecda884..a37ab16d3 100644 Binary files a/public/screenshots/hero.png and b/public/screenshots/hero.png differ diff --git a/public/screenshots/private-resources.png b/public/screenshots/private-resources.png index 9f46544ae..512aa0760 100644 Binary files a/public/screenshots/private-resources.png and b/public/screenshots/private-resources.png differ diff --git a/public/screenshots/public-resources.png b/public/screenshots/public-resources.png index 46ecda884..a37ab16d3 100644 Binary files a/public/screenshots/public-resources.png and b/public/screenshots/public-resources.png differ diff --git a/public/screenshots/sites.png b/public/screenshots/sites.png index 3a4eef8f2..7863cdf9e 100644 Binary files a/public/screenshots/sites.png and b/public/screenshots/sites.png differ diff --git a/server/routers/olm/dnsConfig.ts b/server/routers/olm/dnsConfig.ts new file mode 100644 index 000000000..441246764 --- /dev/null +++ b/server/routers/olm/dnsConfig.ts @@ -0,0 +1,20 @@ +import config from "@server/lib/config"; + +// Mirrors the optional fields on the olm client's TunnelConfig - any field +// present here overrides the value the olm client is otherwise locally +// configured with; an absent field leaves the client's own config alone. +export type OlmDnsConfig = { + upstreamDns?: string[]; + overrideDns?: boolean; + tunnelDns?: boolean; + matchDomains?: string[]; +}; + +export function buildOlmDnsConfig(): OlmDnsConfig | undefined { + return { + upstreamDns: undefined, + overrideDns: undefined, + tunnelDns: undefined, + matchDomains: undefined + }; +} diff --git a/server/routers/olm/handleOlmRegisterMessage.ts b/server/routers/olm/handleOlmRegisterMessage.ts index 35fb95ca5..693920950 100644 --- a/server/routers/olm/handleOlmRegisterMessage.ts +++ b/server/routers/olm/handleOlmRegisterMessage.ts @@ -15,6 +15,7 @@ import { encodeHexLowerCase } from "@oslojs/encoding"; import { sha256 } from "@oslojs/crypto/sha2"; import { getUserDeviceName } from "@server/db/names"; import { buildSiteConfigurationForOlmClient } from "./buildConfiguration"; +import { buildOlmDnsConfig } from "./dnsConfig"; import { OlmErrorCodes, sendOlmError } from "./error"; import { handleFingerprintInsertion } from "./fingerprintingUtils"; import { build } from "@server/build"; @@ -512,6 +513,7 @@ export const handleOlmRegisterMessage: MessageHandler = async (context) => { tunnelIP: `${clientSubnet.split("/")[0]}/${exitNode.address.split("/")[1]}` // we need to use the exit node's subnet mask here because the client will be using the exit node's subnet mask for its routing table so we can address it } : undefined, + dnsConfig: buildOlmDnsConfig(), chainId: chainId } }, diff --git a/src/app/[orgId]/settings/access/users/create/page.tsx b/src/app/[orgId]/settings/access/users/create/page.tsx index 4f6a2b974..b0e0fb681 100644 --- a/src/app/[orgId]/settings/access/users/create/page.tsx +++ b/src/app/[orgId]/settings/access/users/create/page.tsx @@ -13,7 +13,12 @@ import { StrategyOption, StrategySelect } from "@app/components/StrategySelect"; import HeaderTitle from "@app/components/SettingsSectionTitle"; import { Button } from "@app/components/ui/button"; import { useParams, useRouter } from "next/navigation"; -import { useActionState, useRef, useState } from "react"; +import { + useActionState, + useRef, + useState, + startTransition +} from "react"; import { Form, FormControl, @@ -518,9 +523,12 @@ export default function Page() {
{ + e.preventDefault(); + startTransition(() => { + submitInternalAction(); + }); + }} className="space-y-4" id="create-user-form" > diff --git a/src/app/[orgId]/settings/general/page.tsx b/src/app/[orgId]/settings/general/page.tsx index 375592fc5..1171b495f 100644 --- a/src/app/[orgId]/settings/general/page.tsx +++ b/src/app/[orgId]/settings/general/page.tsx @@ -3,7 +3,12 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { Button } from "@app/components/ui/button"; import { useOrgContext } from "@app/hooks/useOrgContext"; import { toast } from "@app/hooks/useToast"; -import { useState, useTransition, useActionState } from "react"; +import { + useState, + useTransition, + useActionState, + startTransition +} from "react"; import { Form, FormControl, @@ -243,7 +248,12 @@ function GeneralSectionForm({ org }: SectionFormProps) { { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} className="grid gap-4" id="org-general-settings-form" > diff --git a/src/app/[orgId]/settings/general/security/page.tsx b/src/app/[orgId]/settings/general/security/page.tsx index 4ffb9fe22..9c1d012c9 100644 --- a/src/app/[orgId]/settings/general/security/page.tsx +++ b/src/app/[orgId]/settings/general/security/page.tsx @@ -3,7 +3,13 @@ import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { Button } from "@app/components/ui/button"; import { useOrgContext } from "@app/hooks/useOrgContext"; import { toast } from "@app/hooks/useToast"; -import { useState, useRef, useActionState, type ComponentRef } from "react"; +import { + useState, + useRef, + useActionState, + startTransition, + type ComponentRef +} from "react"; import { Form, FormControl, @@ -207,7 +213,9 @@ function LogRetentionSectionForm({ org }: SectionFormProps) { { e.preventDefault(); - formAction(); + startTransition(() => { + formAction(); + }); }} className="grid gap-4" id="org-log-retention-settings-form" @@ -959,7 +967,9 @@ function SecuritySettingsSectionForm({ org }: SectionFormProps) { { e.preventDefault(); - formAction(); + startTransition(() => { + formAction(); + }); }} ref={formRef} id="security-settings-section-form" diff --git a/src/app/[orgId]/settings/resources/private/[niceId]/ai-gateway/page.tsx b/src/app/[orgId]/settings/resources/private/[niceId]/ai-gateway/page.tsx index 8907c442d..34830cab5 100644 --- a/src/app/[orgId]/settings/resources/private/[niceId]/ai-gateway/page.tsx +++ b/src/app/[orgId]/settings/resources/private/[niceId]/ai-gateway/page.tsx @@ -41,7 +41,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import { useTranslations } from "next-intl"; import { useRouter } from "next/navigation"; -import { useActionState, useEffect, useMemo } from "react"; +import { useActionState, useEffect, useMemo, startTransition } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -232,7 +232,12 @@ export default function PrivateResourceInferencePage() { { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} id="private-resource-providers-form" > diff --git a/src/app/[orgId]/settings/resources/private/[niceId]/general/page.tsx b/src/app/[orgId]/settings/resources/private/[niceId]/general/page.tsx index 67b0a3b83..442d019dc 100644 --- a/src/app/[orgId]/settings/resources/private/[niceId]/general/page.tsx +++ b/src/app/[orgId]/settings/resources/private/[niceId]/general/page.tsx @@ -29,7 +29,7 @@ import { zodResolver } from "@hookform/resolvers/zod"; import { useTranslations } from "next-intl"; import Link from "next/link"; import { ExternalLink } from "lucide-react"; -import { useActionState, useMemo } from "react"; +import { useActionState, useMemo, startTransition } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; import { useSaveSiteResource } from "@app/hooks/useSaveSiteResource"; @@ -97,7 +97,12 @@ export default function PrivateResourceGeneralPage() { { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} id="private-resource-general-form" > diff --git a/src/app/[orgId]/settings/resources/public/[niceId]/general/page.tsx b/src/app/[orgId]/settings/resources/public/[niceId]/general/page.tsx index c92c5dcd4..33e54a9b9 100644 --- a/src/app/[orgId]/settings/resources/public/[niceId]/general/page.tsx +++ b/src/app/[orgId]/settings/resources/public/[niceId]/general/page.tsx @@ -41,7 +41,13 @@ import { AxiosResponse } from "axios"; import { useTranslations } from "next-intl"; import { useParams, useRouter } from "next/navigation"; import { toASCII, toUnicode } from "punycode"; -import { useActionState, useEffect, useMemo, useState } from "react"; +import { + useActionState, + useEffect, + useMemo, + useState, + startTransition +} from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import z from "zod"; @@ -282,7 +288,12 @@ export default function GeneralForm() { { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} id="general-settings-form" > diff --git a/src/app/[orgId]/settings/resources/public/[niceId]/http/page.tsx b/src/app/[orgId]/settings/resources/public/[niceId]/http/page.tsx index e991d7b97..a38176210 100644 --- a/src/app/[orgId]/settings/resources/public/[niceId]/http/page.tsx +++ b/src/app/[orgId]/settings/resources/public/[niceId]/http/page.tsx @@ -41,7 +41,7 @@ import { import { AxiosResponse } from "axios"; import { useTranslations } from "next-intl"; import { useParams, useRouter } from "next/navigation"; -import { useActionState, useState } from "react"; +import { useActionState, useState, startTransition } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -209,7 +209,15 @@ function ProxyResourceHttpForm({ - + { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} + id="http-settings-form" + > {!env.flags.usePangolinDns && ( diff --git a/src/app/[orgId]/settings/resources/public/[niceId]/maintenance/page.tsx b/src/app/[orgId]/settings/resources/public/[niceId]/maintenance/page.tsx index 8e2d100f5..cdeadec41 100644 --- a/src/app/[orgId]/settings/resources/public/[niceId]/maintenance/page.tsx +++ b/src/app/[orgId]/settings/resources/public/[niceId]/maintenance/page.tsx @@ -37,7 +37,7 @@ import { AxiosResponse } from "axios"; import { AlertCircle } from "lucide-react"; import { useTranslations } from "next-intl"; import { useParams, useRouter } from "next/navigation"; -import { useActionState, useEffect } from "react"; +import { useActionState, useEffect, startTransition } from "react"; import { useForm } from "react-hook-form"; import { zodResolver } from "@hookform/resolvers/zod"; import z from "zod"; @@ -203,7 +203,12 @@ export default function ResourceMaintenancePage() { { + e.preventDefault(); + startTransition(() => { + maintenanceFormAction(); + }); + }} id="maintenance-settings-form" > diff --git a/src/app/[orgId]/settings/resources/public/[niceId]/tcp/page.tsx b/src/app/[orgId]/settings/resources/public/[niceId]/tcp/page.tsx index dc30b2b57..9c8776106 100644 --- a/src/app/[orgId]/settings/resources/public/[niceId]/tcp/page.tsx +++ b/src/app/[orgId]/settings/resources/public/[niceId]/tcp/page.tsx @@ -48,7 +48,8 @@ import { useRouter } from "next/navigation"; import { use, useActionState, - useMemo + useMemo, + startTransition } from "react"; import { useForm } from "react-hook-form"; import { z } from "zod"; @@ -206,7 +207,12 @@ function ProxyResourceProtocolForm({ { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} id="proxy-protocol-settings-form" > diff --git a/src/components/OrgLabelForm.tsx b/src/components/OrgLabelForm.tsx index 1f4bb5359..1413e0ef1 100644 --- a/src/components/OrgLabelForm.tsx +++ b/src/components/OrgLabelForm.tsx @@ -62,7 +62,8 @@ export function OrgLabelForm({ { + onSubmit={async (e) => { + e.preventDefault(); if (await form.trigger()) { onSubmit(form.getValues()); } diff --git a/src/components/alert-rule-editor/AlertRuleGraphEditor.tsx b/src/components/alert-rule-editor/AlertRuleGraphEditor.tsx index 4cc379c29..7ead55447 100644 --- a/src/components/alert-rule-editor/AlertRuleGraphEditor.tsx +++ b/src/components/alert-rule-editor/AlertRuleGraphEditor.tsx @@ -211,7 +211,15 @@ export default function AlertRuleGraphEditor({ return ( - + { + e.preventDefault(); + startTransition(() => { + formAction(); + }); + }} + >