feat: refactor several components and clean up ui

This commit is contained in:
Aarnav Tale
2026-03-09 22:09:58 -04:00
parent a53fd31d27
commit 6470f5a821
49 changed files with 1522 additions and 1355 deletions
@@ -1,4 +1,5 @@
import { Key, useEffect, useRef, useState } from "react";
import type { Key } from "react";
import { useEffect, useRef, useState } from "react";
import { useFetcher } from "react-router";
import Button from "~/components/Button";
@@ -21,9 +22,13 @@ interface AddAuthKeyProps {
}
function findCurrentUser(users: User[], subject: string | undefined): User | undefined {
if (!subject) return undefined;
if (!subject) {
return undefined;
}
return users.find((u) => {
if (u.provider !== "oidc" || !u.providerId) return false;
if (u.provider !== "oidc" || !u.providerId) {
return false;
}
return u.providerId.split("/").pop() === subject;
});
}
@@ -76,7 +81,9 @@ export default function AddAuthKey({
<Dialog
isOpen={isOpen}
onOpenChange={(open) => {
if (!open && submittingRef.current) return;
if (!open && submittingRef.current) {
return;
}
setIsOpen(open);
}}
>
@@ -203,11 +210,7 @@ export default function AddAuthKey({
<Dialog.Text className="text-sm">
Devices authenticated with this key will be automatically removed once they go
offline.{" "}
<Link
isExternal
name="Tailscale Ephemeral Nodes Documentation"
to="https://tailscale.com/kb/1111/ephemeral-nodes"
>
<Link external styled to="https://tailscale.com/kb/1111/ephemeral-nodes">
Learn more
</Link>
</Dialog.Text>
+11 -15
View File
@@ -32,7 +32,7 @@ export async function loader({ request, context }: Route.LoaderArgs) {
try {
allKeys = await api.getAllPreAuthKeys();
} catch {
// older versions don't support this endpoint
// Older versions don't support this endpoint
}
if (allKeys !== null) {
@@ -47,12 +47,12 @@ export async function loader({ request, context }: Route.LoaderArgs) {
keys = [];
const tagOnly = keysByUser.get(null);
if (tagOnly?.length) {
keys.push({ user: null, preAuthKeys: tagOnly });
keys.push({ preAuthKeys: tagOnly, user: null });
}
for (const user of users) {
const userKeys = keysByUser.get(user.id);
if (userKeys?.length) {
keys.push({ user, preAuthKeys: userKeys });
keys.push({ preAuthKeys: userKeys, user });
}
}
} else {
@@ -66,34 +66,34 @@ export async function loader({ request, context }: Route.LoaderArgs) {
.map(async (user) => {
try {
const preAuthKeys = await api.getPreAuthKeys(user.id);
return { success: true as const, user, preAuthKeys };
return { preAuthKeys, success: true as const, user };
} catch (error) {
log.error("api", "GET /v1/preauthkey for %s: %o", user.name, error);
return { success: false as const, user, error, preAuthKeys: [] as const };
return { error, preAuthKeys: [] as const, success: false as const, user };
}
}),
);
keys = results
.filter(({ success }) => success)
.map(({ user, preAuthKeys }) => ({ user, preAuthKeys }));
.map(({ user, preAuthKeys }) => ({ preAuthKeys, user }));
missing = results
.filter((r): r is Extract<FetchResult, { success: false }> => !r.success)
.map(({ user, error }) => ({ user, error }));
.map(({ user, error }) => ({ error, user }));
}
const canGenerateAny = context.auth.can(principal, Capabilities.generate_authkeys);
const canGenerateOwn = context.auth.can(principal, Capabilities.generate_own_authkeys);
return {
access: canGenerateAny || canGenerateOwn,
currentSubject: principal.kind === "oidc" ? principal.user.subject : undefined,
keys,
missing,
users,
access: canGenerateAny || canGenerateOwn,
selfServiceOnly: !canGenerateAny && canGenerateOwn,
currentSubject: principal.kind === "oidc" ? principal.user.subject : undefined,
url: context.config.headscale.public_url ?? context.config.headscale.url,
users,
};
}
@@ -192,11 +192,7 @@ export default function Page({
<p className="mb-4">
Headscale fully supports pre-authentication keys in order to easily add devices to your
Tailnet. To learn more about using pre-authentication keys, visit the{" "}
<Link
isExternal
name="Tailscale Auth Keys documentation"
to="https://tailscale.com/kb/1085/auth-keys/"
>
<Link external styled to="https://tailscale.com/kb/1085/auth-keys/">
Tailscale documentation
</Link>
</p>
+2 -10
View File
@@ -28,11 +28,7 @@ export default function Page({ loaderData: { config, isOidcEnabled } }: Route.Co
<p>
Headscale fully supports pre-authentication keys in order to easily add devices to your
Tailnet. To learn more about using pre-authentication keys, visit the{" "}
<Link
isExternal
name="Tailscale Auth Keys documentation"
to="https://tailscale.com/kb/1085/auth-keys/"
>
<Link external styled to="https://tailscale.com/kb/1085/auth-keys/">
Tailscale documentation
</Link>
</p>
@@ -52,11 +48,7 @@ export default function Page({ loaderData: { config, isOidcEnabled } }: Route.Co
domains, groups, or users to authenticate. This can be used to limit access to your
Tailnet to only certain users or groups and Headplane will also respect these settings
when authenticating.{" "}
<Link
isExternal
name="Headscale OIDC documentation"
to="https://headscale.net/stable/ref/oidc/#basic-configuration"
>
<Link external styled to="https://headscale.net/stable/ref/oidc/#basic-configuration">
Learn More
</Link>
</p>
@@ -28,12 +28,12 @@ export async function loader({ request, context }: Route.LoaderArgs) {
return {
access: context.auth.can(principal, Capabilities.configure_iam),
writable: context.hs.writable(),
settings: {
domains: [...new Set(context.hs.c.oidc.allowed_domains)],
groups: [...new Set(context.hs.c.oidc.allowed_groups)],
users: [...new Set(context.hs.c.oidc.allowed_users)],
},
writable: context.hs.writable(),
};
}
@@ -69,11 +69,7 @@ export default function Page({ loaderData: { access, writable, settings } }: Rou
groups, or users to authenticate. This can be used to limit access to your Tailnet to only
certain users or groups and Headplane will also respect these settings when
authenticating.{" "}
<Link
isExternal
name="Headscale OIDC documentation"
to="https://headscale.net/stable/ref/oidc/#basic-configuration"
>
<Link external styled to="https://headscale.net/stable/ref/oidc/#basic-configuration">
Learn More
</Link>
</p>