Link invite trace accounts to admin user profiles
Magent CI/CD / verify (push) Successful in 10m26s
Magent CI/CD / deploy-prod (push) Skipped
Magent CI/CD / deploy-beta (push) Successful in 1m54s

This commit is contained in:
2026-09-06 22:47:16 +12:00
parent 625f9ad7f0
commit 98d8b197a9
2 changed files with 25 additions and 4 deletions
+13 -4
View File
@@ -1,6 +1,7 @@
'use client' 'use client'
import InviteDeliveryChoice from '../../ui/InviteDeliveryChoice' import InviteDeliveryChoice from '../../ui/InviteDeliveryChoice'
import Link from 'next/link'
import { useRouter } from 'next/navigation' import { useRouter } from 'next/navigation'
import { useEffect, useMemo, useState } from 'react' import { useEffect, useMemo, useState } from 'react'
@@ -918,6 +919,14 @@ export default function AdminInviteManagementPage() {
return invites return invites
}, [inviteView, invites]) }, [inviteView, invites])
const traceUserIds = useMemo(() => new Map(users.map(user => [user.username.trim().toLowerCase(), user.id])), [users])
const traceAccountLink = (username: string, className?: string) => {
const id = traceUserIds.get(username.trim().toLowerCase())
return id != null
? <Link className={`invite-trace-account-link ${className || ''}`} href={`/users/${id}`} title={`Manage ${username}'s account`}>{username}</Link>
: <span className={className}>{username}</span>
}
const inviteTraceRows = useMemo(() => { const inviteTraceRows = useMemo(() => {
const inviteByCode = new Map<string, Invite>() const inviteByCode = new Map<string, Invite>()
invites.forEach((invite) => { invites.forEach((invite) => {
@@ -2276,14 +2285,14 @@ export default function AdminInviteManagementPage() {
> >
<div className="invite-trace-node-main"> <div className="invite-trace-node-main">
<div className="invite-trace-node-title"> <div className="invite-trace-node-title">
<span className="invite-trace-user">{row.username}</span> {traceAccountLink(row.username, 'invite-trace-user')}
<span className={`small-pill ${row.role === 'admin' ? '' : 'is-muted'}`}>{row.role}</span> <span className={`small-pill ${row.role === 'admin' ? '' : 'is-muted'}`}>{row.role}</span>
<span className="small-pill">{row.authProvider}</span> <span className="small-pill">{row.authProvider}</span>
{row.isCycle && <span className="small-pill is-muted">cycle</span>} {row.isCycle && <span className="small-pill is-muted">cycle</span>}
</div> </div>
<p className={`invite-trace-node-arrow ${isInviteTraceRowInvited(row) ? '' : 'is-root'}`}> <p className={`invite-trace-node-arrow ${isInviteTraceRowInvited(row) ? '' : 'is-root'}`}>
{row.inviterUsername {row.inviterUsername
? `\u2190 Invited by ${row.inviterUsername}` ? <> Invited by {traceAccountLink(row.inviterUsername)}</>
: row.inviteCode : row.inviteCode
? `\u2190 Invited via code ${row.inviteCode}` ? `\u2190 Invited via code ${row.inviteCode}`
: 'Direct/root account'} : 'Direct/root account'}
@@ -2319,7 +2328,7 @@ export default function AdminInviteManagementPage() {
<div key={`${row.username}-${row.level}-${row.inviteCode || 'direct'}`} className="invite-trace-row"> <div key={`${row.username}-${row.level}-${row.inviteCode || 'direct'}`} className="invite-trace-row">
<div className="invite-trace-row-main" style={{ paddingLeft: `${row.level * 18}px` }}> <div className="invite-trace-row-main" style={{ paddingLeft: `${row.level * 18}px` }}>
<span className="invite-trace-branch" aria-hidden="true" /> <span className="invite-trace-branch" aria-hidden="true" />
<span className="invite-trace-user">{row.username}</span> {traceAccountLink(row.username, 'invite-trace-user')}
<span className={`small-pill ${row.role === 'admin' ? '' : 'is-muted'}`}>{row.role}</span> <span className={`small-pill ${row.role === 'admin' ? '' : 'is-muted'}`}>{row.role}</span>
<span className="small-pill">{row.authProvider}</span> <span className="small-pill">{row.authProvider}</span>
{row.isCycle && <span className="small-pill is-muted">cycle</span>} {row.isCycle && <span className="small-pill is-muted">cycle</span>}
@@ -2327,7 +2336,7 @@ export default function AdminInviteManagementPage() {
<div className="invite-trace-row-meta"> <div className="invite-trace-row-meta">
<span className="invite-trace-meta-item"> <span className="invite-trace-meta-item">
<span className="label">Invited by</span> <span className="label">Invited by</span>
<strong>{row.inviterUsername || 'Root/direct'}</strong> <strong>{row.inviterUsername ? traceAccountLink(row.inviterUsername) : 'Root/direct'}</strong>
</span> </span>
<span className="invite-trace-meta-item"> <span className="invite-trace-meta-item">
<span className="label">Via code</span> <span className="label">Via code</span>
+12
View File
@@ -5684,6 +5684,18 @@ textarea {
gap: 8px; gap: 8px;
} }
.invite-trace-account-link {
text-decoration: underline;
text-decoration-color: currentColor;
text-underline-offset: 3px;
}
.invite-trace-account-link:focus-visible {
outline: 2px solid currentColor;
outline-offset: 4px;
border-radius: 3px;
}
.invite-trace-graph { .invite-trace-graph {
display: grid; display: grid;
grid-auto-flow: column; grid-auto-flow: column;