Spaces:
Sleeping
Sleeping
Commit ·
4d239f3
1
Parent(s): b0f6b3e
apply new changes
Browse files
src/app/api/contributor/dashboard-summary/route.ts
CHANGED
|
@@ -11,6 +11,27 @@ import { db } from "@/db";
|
|
| 11 |
import { issues } from "@/db/schema";
|
| 12 |
import { eq } from "drizzle-orm";
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
export async function GET(request: NextRequest) {
|
| 15 |
try {
|
| 16 |
const user = await getCurrentUser(request);
|
|
@@ -24,7 +45,7 @@ export async function GET(request: NextRequest) {
|
|
| 24 |
// Fetch all contributor data from the database
|
| 25 |
try {
|
| 26 |
console.log("[Dashboard Summary] Fetching issues for user:", user.username);
|
| 27 |
-
const allItems = await db.select().from(issues).where(eq(issues.authorName, user.username));
|
| 28 |
console.log("[Dashboard Summary] Found %d items", allItems.length);
|
| 29 |
|
| 30 |
// Calculate metrics from database records
|
|
|
|
| 11 |
import { issues } from "@/db/schema";
|
| 12 |
import { eq } from "drizzle-orm";
|
| 13 |
|
| 14 |
+
// Define columns to select (excludes bodySummary which doesn't exist in DB yet)
|
| 15 |
+
const issueColumns = {
|
| 16 |
+
id: issues.id,
|
| 17 |
+
githubIssueId: issues.githubIssueId,
|
| 18 |
+
number: issues.number,
|
| 19 |
+
title: issues.title,
|
| 20 |
+
body: issues.body,
|
| 21 |
+
authorName: issues.authorName,
|
| 22 |
+
repoId: issues.repoId,
|
| 23 |
+
repoName: issues.repoName,
|
| 24 |
+
owner: issues.owner,
|
| 25 |
+
repo: issues.repo,
|
| 26 |
+
htmlUrl: issues.htmlUrl,
|
| 27 |
+
state: issues.state,
|
| 28 |
+
isPR: issues.isPR,
|
| 29 |
+
authorAssociation: issues.authorAssociation,
|
| 30 |
+
headSha: issues.headSha,
|
| 31 |
+
updatedAt: issues.updatedAt,
|
| 32 |
+
createdAt: issues.createdAt,
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
export async function GET(request: NextRequest) {
|
| 36 |
try {
|
| 37 |
const user = await getCurrentUser(request);
|
|
|
|
| 45 |
// Fetch all contributor data from the database
|
| 46 |
try {
|
| 47 |
console.log("[Dashboard Summary] Fetching issues for user:", user.username);
|
| 48 |
+
const allItems = await db.select(issueColumns).from(issues).where(eq(issues.authorName, user.username));
|
| 49 |
console.log("[Dashboard Summary] Found %d items", allItems.length);
|
| 50 |
|
| 51 |
// Calculate metrics from database records
|
src/lib/db/queries/issues.ts
CHANGED
|
@@ -11,17 +11,38 @@ import { issues, triageData, repositories } from "@/db/schema";
|
|
| 11 |
import { eq, and, desc, asc, count, or, like, sql } from "drizzle-orm";
|
| 12 |
import { v4 as uuidv4 } from "uuid";
|
| 13 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 14 |
// =============================================================================
|
| 15 |
// Issue CRUD
|
| 16 |
// =============================================================================
|
| 17 |
|
| 18 |
export async function getIssueById(id: string) {
|
| 19 |
-
const result = await db.select().from(issues).where(eq(issues.id, id)).limit(1);
|
| 20 |
return result[0] || null;
|
| 21 |
}
|
| 22 |
|
| 23 |
export async function getIssueByGithubId(githubIssueId: number) {
|
| 24 |
-
const result = await db.select().from(issues).where(eq(issues.githubIssueId, githubIssueId)).limit(1);
|
| 25 |
return result[0] || null;
|
| 26 |
}
|
| 27 |
|
|
@@ -77,7 +98,7 @@ export async function updateIssueState(id: string, state: string) {
|
|
| 77 |
}
|
| 78 |
|
| 79 |
export async function getIssueByNumberAndRepo(number: number, repoId: string) {
|
| 80 |
-
const result = await db.select().from(issues)
|
| 81 |
.where(and(eq(issues.number, number), eq(issues.repoId, repoId)))
|
| 82 |
.limit(1);
|
| 83 |
return result[0] || null;
|
|
@@ -88,7 +109,7 @@ export async function getIssueByNumberAndRepo(number: number, repoId: string) {
|
|
| 88 |
* Returns the count of deleted duplicates.
|
| 89 |
*/
|
| 90 |
export async function cleanupDuplicateIssues() {
|
| 91 |
-
const allIssues = await db.select().from(issues).orderBy(asc(issues.createdAt));
|
| 92 |
const kept = new Map<string, string>(); // key -> id to keep
|
| 93 |
const toDelete: string[] = [];
|
| 94 |
|
|
@@ -142,7 +163,7 @@ export async function getIssues(filters: IssueFilters, page = 1, limit = 10) {
|
|
| 142 |
if (filters.search) {
|
| 143 |
conditions.push(or(
|
| 144 |
like(issues.title, `%${filters.search}%`),
|
| 145 |
-
like(issues.
|
| 146 |
));
|
| 147 |
}
|
| 148 |
|
|
@@ -173,12 +194,30 @@ export async function getIssues(filters: IssueFilters, page = 1, limit = 10) {
|
|
| 173 |
const totalPages = Math.ceil(total / limit);
|
| 174 |
|
| 175 |
// ✅ SQL-level LIMIT/OFFSET — never materializes full result
|
| 176 |
-
const results = await db.select(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 177 |
.from(issues)
|
| 178 |
.where(whereClause)
|
| 179 |
.orderBy(desc(issues.createdAt))
|
| 180 |
.limit(limit)
|
| 181 |
-
.offset(offset)
|
| 182 |
|
| 183 |
return {
|
| 184 |
issues: results,
|
|
@@ -215,7 +254,7 @@ export async function getIssuesWithTriage(filters: IssueFilters, page = 1, limit
|
|
| 215 |
if (filters.search) {
|
| 216 |
conditions.push(or(
|
| 217 |
like(issues.title, `%${filters.search}%`),
|
| 218 |
-
like(issues.
|
| 219 |
));
|
| 220 |
}
|
| 221 |
|
|
@@ -250,7 +289,7 @@ export async function getIssuesWithTriage(filters: IssueFilters, page = 1, limit
|
|
| 250 |
|
| 251 |
// Fetch issues using simple query
|
| 252 |
console.log("[getIssuesWithTriage] Executing issues query...");
|
| 253 |
-
const issueResults = await db.select()
|
| 254 |
.from(issues)
|
| 255 |
.where(whereClause)
|
| 256 |
.orderBy(desc(issues.createdAt))
|
|
|
|
| 11 |
import { eq, and, desc, asc, count, or, like, sql } from "drizzle-orm";
|
| 12 |
import { v4 as uuidv4 } from "uuid";
|
| 13 |
|
| 14 |
+
// Define columns to select (excludes bodySummary which doesn't exist in DB yet)
|
| 15 |
+
const issueColumns = {
|
| 16 |
+
id: issues.id,
|
| 17 |
+
githubIssueId: issues.githubIssueId,
|
| 18 |
+
number: issues.number,
|
| 19 |
+
title: issues.title,
|
| 20 |
+
body: issues.body,
|
| 21 |
+
authorName: issues.authorName,
|
| 22 |
+
repoId: issues.repoId,
|
| 23 |
+
repoName: issues.repoName,
|
| 24 |
+
owner: issues.owner,
|
| 25 |
+
repo: issues.repo,
|
| 26 |
+
htmlUrl: issues.htmlUrl,
|
| 27 |
+
state: issues.state,
|
| 28 |
+
isPR: issues.isPR,
|
| 29 |
+
authorAssociation: issues.authorAssociation,
|
| 30 |
+
headSha: issues.headSha,
|
| 31 |
+
updatedAt: issues.updatedAt,
|
| 32 |
+
createdAt: issues.createdAt,
|
| 33 |
+
};
|
| 34 |
+
|
| 35 |
// =============================================================================
|
| 36 |
// Issue CRUD
|
| 37 |
// =============================================================================
|
| 38 |
|
| 39 |
export async function getIssueById(id: string) {
|
| 40 |
+
const result = await db.select(issueColumns).from(issues).where(eq(issues.id, id)).limit(1);
|
| 41 |
return result[0] || null;
|
| 42 |
}
|
| 43 |
|
| 44 |
export async function getIssueByGithubId(githubIssueId: number) {
|
| 45 |
+
const result = await db.select(issueColumns).from(issues).where(eq(issues.githubIssueId, githubIssueId)).limit(1);
|
| 46 |
return result[0] || null;
|
| 47 |
}
|
| 48 |
|
|
|
|
| 98 |
}
|
| 99 |
|
| 100 |
export async function getIssueByNumberAndRepo(number: number, repoId: string) {
|
| 101 |
+
const result = await db.select(issueColumns).from(issues)
|
| 102 |
.where(and(eq(issues.number, number), eq(issues.repoId, repoId)))
|
| 103 |
.limit(1);
|
| 104 |
return result[0] || null;
|
|
|
|
| 109 |
* Returns the count of deleted duplicates.
|
| 110 |
*/
|
| 111 |
export async function cleanupDuplicateIssues() {
|
| 112 |
+
const allIssues = await db.select(issueColumns).from(issues).orderBy(asc(issues.createdAt));
|
| 113 |
const kept = new Map<string, string>(); // key -> id to keep
|
| 114 |
const toDelete: string[] = [];
|
| 115 |
|
|
|
|
| 163 |
if (filters.search) {
|
| 164 |
conditions.push(or(
|
| 165 |
like(issues.title, `%${filters.search}%`),
|
| 166 |
+
like(issues.body, `%${filters.search}%`)
|
| 167 |
));
|
| 168 |
}
|
| 169 |
|
|
|
|
| 194 |
const totalPages = Math.ceil(total / limit);
|
| 195 |
|
| 196 |
// ✅ SQL-level LIMIT/OFFSET — never materializes full result
|
| 197 |
+
const results = await db.select({
|
| 198 |
+
id: issues.id,
|
| 199 |
+
githubIssueId: issues.githubIssueId,
|
| 200 |
+
number: issues.number,
|
| 201 |
+
title: issues.title,
|
| 202 |
+
body: issues.body,
|
| 203 |
+
authorName: issues.authorName,
|
| 204 |
+
repoId: issues.repoId,
|
| 205 |
+
repoName: issues.repoName,
|
| 206 |
+
owner: issues.owner,
|
| 207 |
+
repo: issues.repo,
|
| 208 |
+
htmlUrl: issues.htmlUrl,
|
| 209 |
+
state: issues.state,
|
| 210 |
+
isPR: issues.isPR,
|
| 211 |
+
authorAssociation: issues.authorAssociation,
|
| 212 |
+
headSha: issues.headSha,
|
| 213 |
+
updatedAt: issues.updatedAt,
|
| 214 |
+
createdAt: issues.createdAt,
|
| 215 |
+
})
|
| 216 |
.from(issues)
|
| 217 |
.where(whereClause)
|
| 218 |
.orderBy(desc(issues.createdAt))
|
| 219 |
.limit(limit)
|
| 220 |
+
.offset(offset)
|
| 221 |
|
| 222 |
return {
|
| 223 |
issues: results,
|
|
|
|
| 254 |
if (filters.search) {
|
| 255 |
conditions.push(or(
|
| 256 |
like(issues.title, `%${filters.search}%`),
|
| 257 |
+
like(issues.body, `%${filters.search}%`)
|
| 258 |
));
|
| 259 |
}
|
| 260 |
|
|
|
|
| 289 |
|
| 290 |
// Fetch issues using simple query
|
| 291 |
console.log("[getIssuesWithTriage] Executing issues query...");
|
| 292 |
+
const issueResults = await db.select(issueColumns)
|
| 293 |
.from(issues)
|
| 294 |
.where(whereClause)
|
| 295 |
.orderBy(desc(issues.createdAt))
|
src/lib/sync/github-sync.ts
CHANGED
|
@@ -71,7 +71,25 @@ export async function deleteIssueByGithubId(githubIssueId: number): Promise<void
|
|
| 71 |
// =============================================================================
|
| 72 |
|
| 73 |
export async function getIssuesByRepoId(repoId: string) {
|
| 74 |
-
return db.select(
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
}
|
| 76 |
|
| 77 |
// =============================================================================
|
|
|
|
| 71 |
// =============================================================================
|
| 72 |
|
| 73 |
export async function getIssuesByRepoId(repoId: string) {
|
| 74 |
+
return db.select({
|
| 75 |
+
id: issues.id,
|
| 76 |
+
githubIssueId: issues.githubIssueId,
|
| 77 |
+
number: issues.number,
|
| 78 |
+
title: issues.title,
|
| 79 |
+
body: issues.body,
|
| 80 |
+
authorName: issues.authorName,
|
| 81 |
+
repoId: issues.repoId,
|
| 82 |
+
repoName: issues.repoName,
|
| 83 |
+
owner: issues.owner,
|
| 84 |
+
repo: issues.repo,
|
| 85 |
+
htmlUrl: issues.htmlUrl,
|
| 86 |
+
state: issues.state,
|
| 87 |
+
isPR: issues.isPR,
|
| 88 |
+
authorAssociation: issues.authorAssociation,
|
| 89 |
+
headSha: issues.headSha,
|
| 90 |
+
updatedAt: issues.updatedAt,
|
| 91 |
+
createdAt: issues.createdAt,
|
| 92 |
+
}).from(issues).where(eq(issues.repoId, repoId));
|
| 93 |
}
|
| 94 |
|
| 95 |
// =============================================================================
|