import { AlertCircle, Construction, Eye, FlaskConical, Pencil } from "lucide-react"; import { useEffect, useState } from "react"; import { isRouteErrorResponse, useFetcher, useRevalidator } from "react-router"; import Button from "~/components/Button"; import Card from "~/components/Card"; import Code from "~/components/Code"; import Link from "~/components/link"; import Notice from "~/components/Notice"; import PageError from "~/components/page-error"; import Tabs from "~/components/Tabs"; import { isApiError } from "~/server/headscale/api/error-client"; 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"; export const loader = aclLoader; export const action = aclAction; export default function Page({ loaderData: { access, writable, policy } }: Route.ComponentProps) { const [codePolicy, setCodePolicy] = useState(policy); const fetcher = useFetcher(); const { revalidate } = useRevalidator(); const disabled = !access || !writable; // Disable if no permission or not writable useEffect(() => { // Update the codePolicy when the loader data changes if (policy !== codePolicy) { setCodePolicy(policy); } }, [policy]); useEffect(() => { if (!fetcher.data) { // No data yet, return return; } if (fetcher.data.success === true) { toast("Updated policy"); revalidate(); } }, [fetcher.data]); return (
{!access ? ( You do not have the necessary permissions to edit the Access Control List policy. Please contact your administrator to request access or to make changes to the ACL policy. ) : !writable ? ( The ACL policy mode is most likely set to file in your Headscale configuration. This means that the ACL file cannot be edited through the web interface. In order to resolve this, you'll need to set policy.mode to{" "} database in your Headscale configuration. ) : undefined}

Access Control List (ACL)

The ACL file is used to define the access control rules for your network. You can find more information about the ACL file in the{" "} Tailscale ACL guide {" "} and the{" "} Headscale docs .

{fetcher.data?.error !== undefined ? ( {fetcher.data.error.split(":").slice(1).join(": ") ?? "An unknown error occurred while trying to update the ACL policy."} ) : undefined} Edit file
} > Preview changes } > Preview rules } >

Previewing rules is not available yet. This feature is still in development and is pretty complicated to implement. Hopefully I will be able to get to it soon.

); } export function ErrorBoundary({ error }: Route.ErrorBoundaryProps) { if ( isRouteErrorResponse(error) && isApiError(error.data) && error.data.rawData.includes("reading policy from path") && error.data.rawData.includes("no such file or directory") ) { return (
ACL Policy Unavailable
The ACL policy is currently unavailable because the policy file does not exist on the server. This usually indicates that Headscale is running in file mode for ACLs, and the specified policy file is missing.
In order to resolve this issue, there are two possible actions you can take:
  • Create the ACL policy file at the specified path in your Headscale configuration.
  • Alternatively, you can switch Headscale to use database mode for ACLs by updating your Headscale configuration. This will allow Headplane to manage the ACL policy directly through the web interface.
); } return ; }