Dont show raw resource option unless remote node

This commit is contained in:
Owen
2026-03-11 17:47:15 -07:00
parent e5bce4e180
commit 74f4751bcc

View File

@@ -54,6 +54,7 @@ import {
TooltipProvider, TooltipProvider,
TooltipTrigger TooltipTrigger
} from "@app/components/ui/tooltip"; } from "@app/components/ui/tooltip";
import { Alert, AlertDescription, AlertTitle } from "@app/components/ui/alert";
import { useEnvContext } from "@app/hooks/useEnvContext"; import { useEnvContext } from "@app/hooks/useEnvContext";
import { toast } from "@app/hooks/useToast"; import { toast } from "@app/hooks/useToast";
import { createApiClient, formatAxiosError } from "@app/lib/api"; import { createApiClient, formatAxiosError } from "@app/lib/api";
@@ -65,6 +66,7 @@ import { build } from "@server/build";
import { Resource } from "@server/db"; import { Resource } from "@server/db";
import { isTargetValid } from "@server/lib/validators"; import { isTargetValid } from "@server/lib/validators";
import { ListTargetsResponse } from "@server/routers/target"; import { ListTargetsResponse } from "@server/routers/target";
import { ListRemoteExitNodesResponse } from "@server/routers/remoteExitNode/types";
import { ArrayElement } from "@server/types/ArrayElement"; import { ArrayElement } from "@server/types/ArrayElement";
import { useQuery } from "@tanstack/react-query"; import { useQuery } from "@tanstack/react-query";
import { import {
@@ -81,6 +83,7 @@ import {
CircleCheck, CircleCheck,
CircleX, CircleX,
Info, Info,
InfoIcon,
Plus, Plus,
Settings, Settings,
SquareArrowOutUpRight SquareArrowOutUpRight
@@ -210,6 +213,13 @@ export default function Page() {
orgQueries.sites({ orgId: orgId as string }) orgQueries.sites({ orgId: orgId as string })
); );
const [remoteExitNodes, setRemoteExitNodes] = useState<
ListRemoteExitNodesResponse["remoteExitNodes"]
>([]);
const [loadingExitNodes, setLoadingExitNodes] = useState(
build === "saas"
);
const [createLoading, setCreateLoading] = useState(false); const [createLoading, setCreateLoading] = useState(false);
const [showSnippets, setShowSnippets] = useState(false); const [showSnippets, setShowSnippets] = useState(false);
const [niceId, setNiceId] = useState<string>(""); const [niceId, setNiceId] = useState<string>("");
@@ -224,6 +234,27 @@ export default function Page() {
useState<LocalTarget | null>(null); useState<LocalTarget | null>(null);
const [healthCheckDialogOpen, setHealthCheckDialogOpen] = useState(false); const [healthCheckDialogOpen, setHealthCheckDialogOpen] = useState(false);
useEffect(() => {
if (build !== "saas") return;
const fetchExitNodes = async () => {
try {
const res = await api.get<
AxiosResponse<ListRemoteExitNodesResponse>
>(`/org/${orgId}/remote-exit-nodes`);
if (res && res.status === 200) {
setRemoteExitNodes(res.data.data.remoteExitNodes);
}
} catch (e) {
console.error("Failed to fetch remote exit nodes:", e);
} finally {
setLoadingExitNodes(false);
}
};
fetchExitNodes();
}, [orgId]);
const [isAdvancedMode, setIsAdvancedMode] = useState(() => { const [isAdvancedMode, setIsAdvancedMode] = useState(() => {
if (typeof window !== "undefined") { if (typeof window !== "undefined") {
const saved = localStorage.getItem("create-advanced-mode"); const saved = localStorage.getItem("create-advanced-mode");
@@ -288,16 +319,26 @@ export default function Page() {
description: t("resourceHTTPDescription") description: t("resourceHTTPDescription")
}, },
...(!env.flags.allowRawResources ...(!env.flags.allowRawResources
? []
: build === "saas" && remoteExitNodes.length === 0
? [] ? []
: [ : [
{ {
id: "raw" as ResourceType, id: "raw" as ResourceType,
title: t("resourceRaw"), title: t("resourceRaw"),
description: build == "saas" ? t("resourceRawDescriptionCloud") : t("resourceRawDescription") description:
build == "saas"
? t("resourceRawDescriptionCloud")
: t("resourceRawDescription")
} }
]) ])
]; ];
// In saas mode with no exit nodes, force HTTP
const showTypeSelector =
build !== "saas" ||
(!loadingExitNodes && remoteExitNodes.length > 0);
const baseForm = useForm({ const baseForm = useForm({
resolver: zodResolver(baseResourceFormSchema), resolver: zodResolver(baseResourceFormSchema),
defaultValues: { defaultValues: {
@@ -984,7 +1025,8 @@ export default function Page() {
</SettingsSectionTitle> </SettingsSectionTitle>
</SettingsSectionHeader> </SettingsSectionHeader>
<SettingsSectionBody> <SettingsSectionBody>
{resourceTypes.length > 1 && ( {showTypeSelector &&
resourceTypes.length > 1 && (
<> <>
<div className="mb-2"> <div className="mb-2">
<span className="text-sm font-medium"> <span className="text-sm font-medium">