mirror of
https://github.com/tale/headplane.git
synced 2026-08-29 00:17:13 +00:00
feat: admin UI for Headscale user linking + skip onboarding
- Add 'Link Headscale user' option in user menu (admin-only, OIDC users) - Dialog shows only unclaimed Headscale users - New link_user action in user-actions with claim validation - Onboarding now allows skipping the link step with clear messaging - Users who skip are told they can ask an admin to link later Co-authored-by: Amp <amp@ampcode.com> Amp-Thread-ID: https://ampcode.com/threads/T-019cce57-c9e1-7732-9709-8288127573a9
This commit is contained in:
@@ -0,0 +1,58 @@
|
||||
import Dialog from "~/components/Dialog";
|
||||
import Notice from "~/components/Notice";
|
||||
import type { User } from "~/types";
|
||||
import cn from "~/utils/cn";
|
||||
|
||||
interface LinkUserProps {
|
||||
user: User & { headplaneRole: string };
|
||||
headscaleUsers: { id: string; name: string }[];
|
||||
currentLink?: string;
|
||||
isOpen: boolean;
|
||||
setIsOpen: (isOpen: boolean) => void;
|
||||
}
|
||||
|
||||
export default function LinkUser({
|
||||
user,
|
||||
headscaleUsers,
|
||||
currentLink,
|
||||
isOpen,
|
||||
setIsOpen,
|
||||
}: LinkUserProps) {
|
||||
return (
|
||||
<Dialog isOpen={isOpen} onOpenChange={setIsOpen}>
|
||||
<Dialog.Panel>
|
||||
<Dialog.Title>Link Headscale user for {user.name || user.displayName}</Dialog.Title>
|
||||
<Dialog.Text className="mb-6">
|
||||
Select which Headscale user this OIDC identity should be linked to. This controls which
|
||||
machines they can manage and enables self-service features.
|
||||
</Dialog.Text>
|
||||
{headscaleUsers.length === 0 ? (
|
||||
<Notice>All Headscale users are already linked to other accounts.</Notice>
|
||||
) : (
|
||||
<>
|
||||
<input name="action_id" type="hidden" value="link_user" />
|
||||
<input name="user_id" type="hidden" value={user.id} />
|
||||
<select
|
||||
className={cn(
|
||||
"w-full rounded-lg border p-2",
|
||||
"border-headplane-200 dark:border-headplane-700",
|
||||
"bg-headplane-50 dark:bg-headplane-900",
|
||||
)}
|
||||
defaultValue={currentLink ?? ""}
|
||||
name="headscale_user_id"
|
||||
required
|
||||
>
|
||||
<option value="">Select a Headscale user...</option>
|
||||
{headscaleUsers.map((u) => (
|
||||
<option key={u.id} value={u.id}>
|
||||
{u.name}
|
||||
{u.id === currentLink ? " (current)" : ""}
|
||||
</option>
|
||||
))}
|
||||
</select>
|
||||
</>
|
||||
)}
|
||||
</Dialog.Panel>
|
||||
</Dialog>
|
||||
);
|
||||
}
|
||||
Reference in New Issue
Block a user