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:
Aarnav Tale
2026-03-08 00:51:23 -05:00
parent 684a95b5e8
commit 434f886034
7 changed files with 277 additions and 93 deletions
+19
View File
@@ -339,6 +339,25 @@ export class AuthService {
return true;
}
/**
* Link a Headplane user (identified by OIDC subject) to a Headscale
* user. Used by admin UI when subjects are more accessible than
* internal Headplane IDs. Returns false if already claimed.
*/
async linkHeadscaleUserBySubject(subject: string, headscaleUserId: string): Promise<boolean> {
const [user] = await this.opts.db
.select({ id: users.id })
.from(users)
.where(eq(users.sub, subject))
.limit(1);
if (!user) {
return false;
}
return this.linkHeadscaleUser(user.id, headscaleUserId);
}
/**
* Returns the set of Headscale user IDs that are already claimed
* by a Headplane user. Used to filter the onboarding dropdown.