Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions src/routes/dashboard/admin/print/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { db } from '$lib/server/db/index.js';
import { project, user, devlog } from '$lib/server/db/schema.js';
import { project, user, devlog, legionReview } from '$lib/server/db/schema.js';
import { error } from '@sveltejs/kit';
import { eq, and, sql, ne, inArray } from 'drizzle-orm';
import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm';
import type { Actions } from './$types';
import { getCurrentlyPrinting } from './utils.server';

Expand Down Expand Up @@ -31,13 +31,34 @@ export async function load({ locals }) {
.from(user)
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users

const legionAgg = db
.$with('legionAgg')
.as(
db
.select({ userId: legionReview.userId, legionCnt: sql<number>`COUNT(*)`.as('legionCnt') })
.from(legionReview)
.groupBy(legionReview.userId)
);

const totalExpr = sql<number>`COALESCE(${legionAgg.legionCnt}, 0)`;

const leaderboard = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Comment on lines +34 to +52
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.

Comment on lines +45 to +53
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'review_count' is misleading in this context. Since this leaderboard tracks printing actions (as indicated by the query using legionReview table), it should be renamed to something like 'print_count' or 'action_count' to accurately reflect what's being counted.

Suggested change
const leaderboard = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
const leaderboardRaw = await db
.with(legionAgg)
.select({ id: user.id, name: user.name, print_count: totalExpr })
.from(user)
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
const leaderboard = leaderboardRaw.map((entry) => ({
...entry,
review_count: entry.print_count
}));

Copilot uses AI. Check for mistakes.
const currentlyPrinting = await getCurrentlyPrinting(locals.user);

return {
allProjects,
projects,
users,
currentlyPrinting
currentlyPrinting,
leaderboard
};
}

Expand Down
39 changes: 23 additions & 16 deletions src/routes/dashboard/admin/print/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -123,22 +123,29 @@
</div>
<div class="themed-box grow p-3 lg:min-w-[30%]">
<h2 class="text-xl font-bold">Leaderboard</h2>
<div class="w-full overflow-scroll">
Coming soon!
<!-- <table class="w-full">
<thead>
<tr>
<th align="left">a</th>
<th align="right">a</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">a</td>
<td align="right">a</td>
</tr>
</tbody>
</table> -->
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Printer</th>
<th class="py-1" align="right">Number of prints</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
Comment on lines +136 to +141
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The variable name 'review_count' is misleading in this context. Since this leaderboard tracks printing actions (as indicated by the column header "Number of prints" and the empty state message "No printing actions yet."), it should be renamed to something like 'print_count' or 'action_count' for clarity.

Suggested change
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
{#each data.leaderboard as { id, name, review_count: print_count }}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${id}`}>{name}</a>
</td>
<td class="py-1" align="right">{print_count}</td>

Copilot uses AI. Check for mistakes.
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No printing actions yet.</p>
{/if}
Comment on lines +126 to +148
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
</div>
</div>
</div>
Expand Down
47 changes: 44 additions & 3 deletions src/routes/dashboard/admin/review/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { db } from '$lib/server/db/index.js';
import { project, user, devlog } from '$lib/server/db/schema.js';
import { project, user, devlog, t1Review, legionReview, t2Review } from '$lib/server/db/schema.js';
import { error } from '@sveltejs/kit';
import { eq, and, sql, ne, inArray } from 'drizzle-orm';
import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm';
import type { Actions } from './$types';

export async function load({ locals }) {
Expand Down Expand Up @@ -30,10 +30,51 @@ export async function load({ locals }) {
.from(user)
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users

const t1Agg = db
.$with('t1Agg')
.as(
db
.select({ userId: t1Review.userId, t1Cnt: sql<number>`COUNT(*)`.as('t1Cnt') })
.from(t1Review)
.groupBy(t1Review.userId)
);

const legionAgg = db
.$with('legionAgg')
.as(
db
.select({ userId: legionReview.userId, legionCnt: sql<number>`COUNT(*)`.as('legionCnt') })
.from(legionReview)
.groupBy(legionReview.userId)
);

const t2Agg = db
.$with('t2Agg')
.as(
db
.select({ userId: t2Review.userId, t2Cnt: sql<number>`COUNT(*)`.as('t2Cnt') })
.from(t2Review)
.groupBy(t2Review.userId)
);

const totalExpr = sql<number>`COALESCE(${t1Agg.t1Cnt}, 0) + COALESCE(${legionAgg.legionCnt}, 0) + COALESCE(${t2Agg.t2Cnt}, 0)`;

const leaderboard = await db
.with(t1Agg, legionAgg, t2Agg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(t1Agg, eq(t1Agg.userId, user.id))
.leftJoin(legionAgg, eq(legionAgg.userId, user.id))
.leftJoin(t2Agg, eq(t2Agg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Comment on lines +33 to +71
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.

return {
allProjects,
projects,
users
users,
leaderboard
};
}

Expand Down
41 changes: 24 additions & 17 deletions src/routes/dashboard/admin/review/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -111,27 +111,34 @@
</div>
<div class="themed-box grow p-3 lg:min-w-[30%]">
<h2 class="text-xl font-bold">Leaderboard</h2>
<div class="w-full overflow-scroll">
Coming soon!
<!-- <table class="w-full">
<thead>
<tr>
<th align="left">a</th>
<th align="right">a</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">a</td>
<td align="right">a</td>
</tr>
</tbody>
</table> -->
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Reviewer</th>
<th class="py-1" align="right">Reviews</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>
</td>
<td class="py-1" align="right">{row.review_count}</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No reviews yet.</p>
{/if}
Comment on lines +114 to +136
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
</div>
</div>
</div>

<h2 class="mt-4 mb-2 text-2xl font-bold">Projects</h2>
<h2 class="mt-4 mb-2 text-2xl font-bold">Projects <span class="ml-2 align-middle text-sm font-normal">({projects.length})</span></h2>

{#if projects.length == 0}
<div class="flex grow items-center justify-center">
Expand Down
27 changes: 24 additions & 3 deletions src/routes/dashboard/admin/ysws-review/+page.server.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { db } from '$lib/server/db/index.js';
import { project, user, devlog } from '$lib/server/db/schema.js';
import { project, user, devlog, t2Review } from '$lib/server/db/schema.js';
import { error } from '@sveltejs/kit';
import { eq, and, sql, ne, inArray } from 'drizzle-orm';
import { eq, and, sql, ne, inArray, desc, gt } from 'drizzle-orm';
import type { Actions } from './$types';

export async function load({ locals }) {
Expand Down Expand Up @@ -30,10 +30,31 @@ export async function load({ locals }) {
.from(user)
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'))); // hide banned users

const t2Agg = db
.$with('t2Agg')
.as(
db
.select({ userId: t2Review.userId, t2Cnt: sql<number>`COUNT(*)`.as('t2Cnt') })
.from(t2Review)
.groupBy(t2Review.userId)
);

const totalExpr = sql<number>`COALESCE(${t2Agg.t2Cnt}, 0)`;

const leaderboard = await db
.with(t2Agg)
.select({ id: user.id, name: user.name, review_count: totalExpr })
.from(user)
.leftJoin(t2Agg, eq(t2Agg.userId, user.id))
.where(and(ne(user.trust, 'red'), ne(user.hackatimeTrust, 'red'), gt(totalExpr, 0)))
.orderBy(desc(totalExpr))
.limit(10);
Comment on lines +33 to +51
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard query pattern is duplicated across three files (ysws-review, review, and print +page.server.ts). Consider extracting this into a shared utility function that accepts the review tables and optional filters as parameters to improve maintainability and reduce code duplication.

Copilot uses AI. Check for mistakes.

return {
allProjects,
projects,
users
users,
leaderboard
};
}

Expand Down
39 changes: 23 additions & 16 deletions src/routes/dashboard/admin/ysws-review/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -111,22 +111,29 @@
</div>
<div class="themed-box grow p-3 lg:min-w-[30%]">
<h2 class="text-xl font-bold">Leaderboard</h2>
<div class="w-full overflow-scroll">
Coming soon!
<!-- <table class="w-full">
<thead>
<tr>
<th align="left">a</th>
<th align="right">a</th>
</tr>
</thead>
<tbody>
<tr>
<td align="left">a</td>
<td align="right">a</td>
</tr>
</tbody>
</table> -->
<div class="w-full overflow-x-auto">
{#if data.leaderboard?.length > 0}
<table class="w-full text-sm">
<thead>
<tr class="text-primary-300">
<th class="py-1" align="left">Reviewer</th>
<th class="py-1" align="right">Reviews</th>
</tr>
</thead>
<tbody>
{#each data.leaderboard as row}
<tr>
<td class="py-1" align="left">
<a class="underline" href={`../users/${row.id}`}>{row.name}</a>
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The URL path uses a relative path '../users/' which may cause navigation issues depending on the current route. Consider using an absolute path '/dashboard/users/' for consistency with the review page implementation (line 127 in review/+page.svelte).

Suggested change
<a class="underline" href={`../users/${row.id}`}>{row.name}</a>
<a class="underline" href={`/dashboard/users/${row.id}`}>{row.name}</a>

Copilot uses AI. Check for mistakes.
</td>
<td class="py-1" align="right">{row.review_count}</td>
</tr>
{/each}
</tbody>
</table>
{:else}
<p class="text-sm text-primary-300">No reviews yet.</p>
{/if}
Comment on lines +114 to +136
Copy link

Copilot AI Dec 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The leaderboard table markup is duplicated across all three admin pages (ysws-review, review, and print). Consider extracting this into a reusable Svelte component that accepts the leaderboard data, column headers, and user type label as props to reduce duplication and improve maintainability.

Copilot uses AI. Check for mistakes.
</div>
</div>
</div>
Expand Down