From 33f7bbb0cffe401417e65a93113a8d02647ab31e Mon Sep 17 00:00:00 2001 From: Aarnav Tale Date: Mon, 6 Apr 2026 22:48:14 -0400 Subject: [PATCH] fix: handle empty ACLs --- app/routes/acls/acl-loader.ts | 5 ++++- app/routes/acls/overview.tsx | 19 +++++++++++++++---- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/app/routes/acls/acl-loader.ts b/app/routes/acls/acl-loader.ts index c1af5ae..24dc3b1 100644 --- a/app/routes/acls/acl-loader.ts +++ b/app/routes/acls/acl-loader.ts @@ -38,8 +38,11 @@ export async function aclLoader({ request, context }: Route.LoaderArgs) { return flags; } catch (error) { if (isDataWithApiError(error)) { + // Headscale returns "acl policy not found" when the policy mode is + // set to file but no file exists, and returns a 500 when database + // mode is used but the policies table is empty. // https://github.com/juanfont/headscale/blob/c4600346f9c29b514dc9725ac103efb9d0381f23/hscontrol/types/policy.go#L10 - if (error.data.rawData.includes("acl policy not found")) { + if (error.data.rawData.includes("acl policy not found") || error.data.statusCode === 500) { flags.policy = ""; flags.writable = true; return flags; diff --git a/app/routes/acls/overview.tsx b/app/routes/acls/overview.tsx index c0471e1..9cddfb2 100644 --- a/app/routes/acls/overview.tsx +++ b/app/routes/acls/overview.tsx @@ -1,5 +1,5 @@ import { AlertCircle, Construction, Eye, FlaskConical, Pencil } from "lucide-react"; -import { useEffect, useState } from "react"; +import { Suspense, lazy, useEffect, useState } from "react"; import { isRouteErrorResponse, useFetcher, useRevalidator } from "react-router"; import Button from "~/components/button"; @@ -15,7 +15,14 @@ import toast from "~/utils/toast"; import type { Route } from "./+types/overview"; import { aclAction } from "./acl-action"; import { aclLoader } from "./acl-loader"; -import { Differ, Editor } from "./components/cm.client"; +import Fallback from "./components/fallback"; + +const LazyEditor = lazy(() => + import("./components/cm.client").then((m) => ({ default: m.Editor })), +); +const LazyDiffer = lazy(() => + import("./components/cm.client").then((m) => ({ default: m.Differ })), +); export const loader = aclLoader; export const action = aclAction; @@ -101,10 +108,14 @@ export default function Page({ loaderData: { access, writable, policy } }: Route - + }> + + - + }> + +