feat: admin can change user display name
API: new updateName adminProcedure in user router - Input: userId + name (min 1, max 200 chars) - Argon2 not involved (name only, not password) - Audit log: "Changed name from X to Y" UI: "Display Name" editable section in user edit modal - Shows current name with "Edit" link - Click Edit: inline input with Save/Cancel + Enter/Escape - Auto-focuses input, saves on Enter - Invalidates user list on success Co-Authored-By: claude-flow <ruv@ruv.net>
This commit is contained in:
@@ -196,6 +196,41 @@ export const userRouter = createTRPCRouter({
|
||||
return updated;
|
||||
}),
|
||||
|
||||
updateName: adminProcedure
|
||||
.input(
|
||||
z.object({
|
||||
id: z.string(),
|
||||
name: z.string().min(1, "Name is required").max(200),
|
||||
}),
|
||||
)
|
||||
.mutation(async ({ ctx, input }) => {
|
||||
const before = await ctx.db.user.findUniqueOrThrow({
|
||||
where: { id: input.id },
|
||||
select: { id: true, name: true, email: true },
|
||||
});
|
||||
|
||||
const updated = await ctx.db.user.update({
|
||||
where: { id: input.id },
|
||||
data: { name: input.name },
|
||||
select: { id: true, name: true, email: true },
|
||||
});
|
||||
|
||||
void createAuditEntry({
|
||||
db: ctx.db,
|
||||
entityType: "User",
|
||||
entityId: updated.id,
|
||||
entityName: `${updated.name} (${updated.email})`,
|
||||
action: "UPDATE",
|
||||
...(ctx.dbUser?.id ? { userId: ctx.dbUser.id } : {}),
|
||||
before: before as unknown as Record<string, unknown>,
|
||||
after: updated as unknown as Record<string, unknown>,
|
||||
source: "ui",
|
||||
summary: `Changed name from "${before.name}" to "${updated.name}"`,
|
||||
});
|
||||
|
||||
return updated;
|
||||
}),
|
||||
|
||||
// ─── Resource Linking ──────────────────────────────────────────────────
|
||||
|
||||
linkResource: adminProcedure
|
||||
|
||||
Reference in New Issue
Block a user