mirror of
https://github.com/Tony0410/readlater.git
synced 2026-05-24 22:01:41 +08:00
Add bulk select and archive, improve performance
- Add database indexes on isArchived, isFavorite, createdAt columns - Optimize article list API to exclude content/textContent fields - Add PATCH /api/articles endpoint for bulk updates - Implement multi-select mode with Select/Deselect all - Add bulk archive/unarchive buttons - Rename "All Articles" to "To Read" - Fetch full article content only when opening for reading Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -2,15 +2,37 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { db, schema } from "@/lib/db";
|
||||
import { extractArticle } from "@/lib/utils/extract";
|
||||
import { v4 as uuidv4 } from "uuid";
|
||||
import { desc, eq } from "drizzle-orm";
|
||||
import { desc, eq, inArray } from "drizzle-orm";
|
||||
|
||||
// GET /api/articles - List all articles
|
||||
// GET /api/articles - List all articles (optimized - excludes content fields)
|
||||
export async function GET(request: NextRequest) {
|
||||
try {
|
||||
const searchParams = request.nextUrl.searchParams;
|
||||
const filter = searchParams.get("filter"); // all, favorites, archived
|
||||
|
||||
let query = db.select().from(schema.articles);
|
||||
// Select only fields needed for list view (exclude large content/textContent)
|
||||
const listFields = {
|
||||
id: schema.articles.id,
|
||||
url: schema.articles.url,
|
||||
title: schema.articles.title,
|
||||
author: schema.articles.author,
|
||||
siteName: schema.articles.siteName,
|
||||
excerpt: schema.articles.excerpt,
|
||||
leadImage: schema.articles.leadImage,
|
||||
wordCount: schema.articles.wordCount,
|
||||
readingProgress: schema.articles.readingProgress,
|
||||
readingTimeSeconds: schema.articles.readingTimeSeconds,
|
||||
isFavorite: schema.articles.isFavorite,
|
||||
isArchived: schema.articles.isArchived,
|
||||
folderId: schema.articles.folderId,
|
||||
tags: schema.articles.tags,
|
||||
createdAt: schema.articles.createdAt,
|
||||
updatedAt: schema.articles.updatedAt,
|
||||
readAt: schema.articles.readAt,
|
||||
finishedAt: schema.articles.finishedAt,
|
||||
};
|
||||
|
||||
let query = db.select(listFields).from(schema.articles);
|
||||
|
||||
if (filter === "favorites") {
|
||||
query = query.where(eq(schema.articles.isFavorite, true)) as typeof query;
|
||||
@@ -33,6 +55,49 @@ export async function GET(request: NextRequest) {
|
||||
}
|
||||
}
|
||||
|
||||
// PATCH /api/articles - Bulk update articles
|
||||
export async function PATCH(request: NextRequest) {
|
||||
try {
|
||||
const body = await request.json();
|
||||
const { ids, updates } = body;
|
||||
|
||||
if (!ids || !Array.isArray(ids) || ids.length === 0) {
|
||||
return NextResponse.json({ error: "Article IDs required" }, { status: 400 });
|
||||
}
|
||||
|
||||
// Only allow certain fields to be bulk updated
|
||||
const allowedUpdates: Partial<typeof schema.articles.$inferInsert> = {};
|
||||
if (typeof updates.isArchived === "boolean") {
|
||||
allowedUpdates.isArchived = updates.isArchived;
|
||||
}
|
||||
if (typeof updates.isFavorite === "boolean") {
|
||||
allowedUpdates.isFavorite = updates.isFavorite;
|
||||
}
|
||||
if (updates.folderId !== undefined) {
|
||||
allowedUpdates.folderId = updates.folderId;
|
||||
}
|
||||
|
||||
if (Object.keys(allowedUpdates).length === 0) {
|
||||
return NextResponse.json({ error: "No valid updates provided" }, { status: 400 });
|
||||
}
|
||||
|
||||
allowedUpdates.updatedAt = new Date();
|
||||
|
||||
await db
|
||||
.update(schema.articles)
|
||||
.set(allowedUpdates)
|
||||
.where(inArray(schema.articles.id, ids));
|
||||
|
||||
return NextResponse.json({ success: true, updated: ids.length });
|
||||
} catch (error) {
|
||||
console.error("Error bulk updating articles:", error);
|
||||
return NextResponse.json(
|
||||
{ error: "Failed to update articles" },
|
||||
{ status: 500 }
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// POST /api/articles - Save a new article
|
||||
export async function POST(request: NextRequest) {
|
||||
try {
|
||||
|
||||
Reference in New Issue
Block a user