all the haul
This commit is contained in:
@@ -37,13 +37,13 @@ export const load: PageServerLoad = async ({ locals }) => {
|
||||
try {
|
||||
const rolesResult = await optima.users.fetchRoles(
|
||||
accessToken,
|
||||
user.id,
|
||||
user.id
|
||||
);
|
||||
return { ...user, roleDetails: rolesResult?.data ?? [] };
|
||||
} catch {
|
||||
return { ...user, roleDetails: [] };
|
||||
}
|
||||
}),
|
||||
})
|
||||
);
|
||||
|
||||
return {
|
||||
@@ -66,21 +66,30 @@ export const actions: Actions = {
|
||||
|
||||
const formData = await request.formData();
|
||||
const id = (formData.get("id") as string)?.trim();
|
||||
const name = (formData.get("name") as string)?.trim();
|
||||
const firstName = (formData.get("firstName") as string)?.trim();
|
||||
const lastName = (formData.get("lastName") as string)?.trim();
|
||||
const image = (formData.get("image") as string)?.trim() || undefined;
|
||||
const rolesJson = (formData.get("roles") as string)?.trim();
|
||||
const permissionsJson = (formData.get("permissions") as string)?.trim();
|
||||
|
||||
if (!id || !name) {
|
||||
return fail(400, { message: "User ID and name are required." });
|
||||
if (!id) {
|
||||
return fail(400, { message: "User ID is required." });
|
||||
}
|
||||
|
||||
const updates: {
|
||||
name: string;
|
||||
firstName?: string | null;
|
||||
lastName?: string | null;
|
||||
image?: string;
|
||||
roles?: string[];
|
||||
permissions?: string[];
|
||||
} = { name, image };
|
||||
} = { image };
|
||||
|
||||
if (formData.has("firstName")) {
|
||||
updates.firstName = firstName || null;
|
||||
}
|
||||
if (formData.has("lastName")) {
|
||||
updates.lastName = lastName || null;
|
||||
}
|
||||
|
||||
if (rolesJson) {
|
||||
try {
|
||||
|
||||
@@ -29,13 +29,18 @@
|
||||
$: users = data.users;
|
||||
$: allRoles = data.roles;
|
||||
|
||||
function fullName(user: UserWithRoles): string {
|
||||
const computed = `${user.firstName ?? ""} ${user.lastName ?? ""}`.trim();
|
||||
return computed || user.name || user.login || user.email;
|
||||
}
|
||||
|
||||
// Search / filter
|
||||
let searchQuery = "";
|
||||
$: filteredUsers = users.filter((u) => {
|
||||
if (!searchQuery.trim()) return true;
|
||||
const q = searchQuery.toLowerCase();
|
||||
return (
|
||||
u.name.toLowerCase().includes(q) ||
|
||||
fullName(u).toLowerCase().includes(q) ||
|
||||
u.email.toLowerCase().includes(q) ||
|
||||
u.login.toLowerCase().includes(q)
|
||||
);
|
||||
@@ -151,8 +156,9 @@
|
||||
onCancel={cancelDelete}
|
||||
handleEnhance={handleDeleteEnhance}
|
||||
>
|
||||
Are you sure you want to delete <strong>{userToDelete?.name}</strong>? This
|
||||
action cannot be undone.
|
||||
Are you sure you want to delete <strong
|
||||
>{userToDelete ? fullName(userToDelete) : "this user"}</strong
|
||||
>? This action cannot be undone.
|
||||
</DeleteConfirmDialog>
|
||||
|
||||
<div class="admin-table-header">
|
||||
@@ -211,15 +217,15 @@
|
||||
{#if user.image}
|
||||
<img
|
||||
src={user.image}
|
||||
alt={user.name}
|
||||
alt={fullName(user)}
|
||||
class="user-table-avatar"
|
||||
/>
|
||||
{:else}
|
||||
<div class="user-table-avatar user-table-avatar-initials">
|
||||
{initials(user.name)}
|
||||
{initials(fullName(user))}
|
||||
</div>
|
||||
{/if}
|
||||
<span class="user-table-name">{user.name}</span>
|
||||
<span class="user-table-name">{fullName(user)}</span>
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
|
||||
@@ -20,6 +20,10 @@ const { mockOptima, mockCheckPermissions, mockHandleApiError, mockFail } =
|
||||
})),
|
||||
}));
|
||||
|
||||
vi.mock("$env/static/public", () => ({
|
||||
PUBLIC_API_URL: "https://api.example.com",
|
||||
}));
|
||||
|
||||
vi.mock("$lib", () => ({ optima: mockOptima }));
|
||||
vi.mock("$lib/permissions", () => ({
|
||||
checkPermissions: mockCheckPermissions,
|
||||
@@ -102,15 +106,15 @@ describe("admin/users +page.server.ts", () => {
|
||||
});
|
||||
});
|
||||
|
||||
it("returns 400 when required fields are missing", async () => {
|
||||
it("returns 400 when user ID is missing", async () => {
|
||||
await actions.updateUser({
|
||||
locals: { session: { accessToken: "tok" } },
|
||||
request: {
|
||||
formData: vi.fn().mockResolvedValue(createFormData({ id: "u1" })),
|
||||
formData: vi.fn().mockResolvedValue(createFormData({})),
|
||||
},
|
||||
} as any);
|
||||
expect(mockFail).toHaveBeenCalledWith(400, {
|
||||
message: "User ID and name are required.",
|
||||
message: "User ID is required.",
|
||||
});
|
||||
});
|
||||
|
||||
@@ -120,14 +124,19 @@ describe("admin/users +page.server.ts", () => {
|
||||
const result = await actions.updateUser({
|
||||
locals: { session: { accessToken: "tok" } },
|
||||
request: {
|
||||
formData: vi
|
||||
.fn()
|
||||
.mockResolvedValue(createFormData({ id: "u1", name: "Updated" })),
|
||||
formData: vi.fn().mockResolvedValue(
|
||||
createFormData({
|
||||
id: "u1",
|
||||
firstName: "Updated",
|
||||
lastName: "User",
|
||||
})
|
||||
),
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(mockOptima.users.update).toHaveBeenCalledWith("tok", "u1", {
|
||||
name: "Updated",
|
||||
firstName: "Updated",
|
||||
lastName: "User",
|
||||
image: undefined,
|
||||
});
|
||||
expect(result).toEqual({});
|
||||
@@ -142,15 +151,17 @@ describe("admin/users +page.server.ts", () => {
|
||||
formData: vi.fn().mockResolvedValue(
|
||||
createFormData({
|
||||
id: "u1",
|
||||
name: "Updated",
|
||||
firstName: "Updated",
|
||||
lastName: "User",
|
||||
roles: '["r1","r2"]',
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
} as any);
|
||||
|
||||
expect(mockOptima.users.update).toHaveBeenCalledWith("tok", "u1", {
|
||||
name: "Updated",
|
||||
firstName: "Updated",
|
||||
lastName: "User",
|
||||
image: undefined,
|
||||
roles: ["r1", "r2"],
|
||||
});
|
||||
@@ -163,9 +174,9 @@ describe("admin/users +page.server.ts", () => {
|
||||
formData: vi.fn().mockResolvedValue(
|
||||
createFormData({
|
||||
id: "u1",
|
||||
name: "Updated",
|
||||
firstName: "Updated",
|
||||
roles: "bad json",
|
||||
}),
|
||||
})
|
||||
),
|
||||
},
|
||||
} as any);
|
||||
|
||||
Reference in New Issue
Block a user