0.3.1 UI修复

This commit is contained in:
liaibo
2026-01-18 19:01:31 +08:00
parent 90a38b48cf
commit 8a5b915002
86 changed files with 1160 additions and 2867 deletions
@@ -1,5 +1,4 @@
import { NextResponse } from "next/server";
import { createSupabaseRouteClient } from "@/lib/supabase/server";
import type { DocumentTableSnapshot, TableRowData } from "@/types/online-table";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
@@ -25,25 +24,12 @@ const extractTableId = async (context: RouteContext) => {
return (await context.params).tableId;
};
const getAuthUser = async () => {
const supabase = await createSupabaseRouteClient();
const { data, error } = await supabase.auth.getUser();
if (error) {
console.error("Auth getUser error:", error);
}
if (!data?.user) {
return { supabase, user: null };
}
return { supabase, user: data.user };
};
export async function GET(request: Request, context: RouteContext) {
export async function GET(_request: Request, context: RouteContext) {
const tableId = await extractTableId(context);
if (!tableId) {
return NextResponse.json({ error: "Missing tableId" }, { status: 400 });
}
// Convex 模式
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
try {
@@ -63,36 +49,7 @@ export async function GET(request: Request, context: RouteContext) {
}
}
// Supabase 模式
const { supabase, user } = await getAuthUser();
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
// 假设 RLS 确保了用户只能访问其有权限的表格
const { data: tableData, error } = await supabase
.from("document_tables")
.select("*")
.eq("id", tableId)
.single();
if (error) {
console.error("Error fetching table:", error);
return NextResponse.json({ error: "Failed to fetch table data" }, { status: 500 });
}
if (!tableData) {
return NextResponse.json({ error: "Table not found" }, { status: 404 });
}
return NextResponse.json(tableData, { status: 200 });
} catch (error) {
console.error("API error:", error);
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });
}
export async function PATCH(request: Request, context: RouteContext) {
@@ -101,13 +58,18 @@ export async function PATCH(request: Request, context: RouteContext) {
return NextResponse.json({ error: "Missing tableId" }, { status: 400 });
}
// Convex 模式
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
let body: UpdateTableRequest;
try {
const body = await request.json() as UpdateTableRequest;
body = (await request.json()) as UpdateTableRequest;
} catch (error) {
console.error("Invalid payload:", error);
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
}
const result = await client.mutation(api.tables.update, {
try {
await client.mutation(api.tables.update, {
userId: auth.userId,
tableId,
title: body.title,
@@ -117,7 +79,6 @@ export async function PATCH(request: Request, context: RouteContext) {
rows: body.rows,
});
// 重新获取更新后的表格数据
const updated = await client.query(api.tables.get, {
userId: auth.userId,
tableId,
@@ -130,125 +91,15 @@ export async function PATCH(request: Request, context: RouteContext) {
}
}
// Supabase 模式
const { supabase, user } = await getAuthUser();
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
let body: UpdateTableRequest | null = null;
try {
body = await request.json() as UpdateTableRequest;
} catch (error) {
console.error("Invalid payload:", error);
return NextResponse.json({ error: "Invalid payload" }, { status: 400 });
}
try {
const { data: tableMeta, error: metaError } = await supabase
.from("document_tables")
.select("id, workspace_id, document_id, grid_key")
.eq("id", tableId)
.single();
if (metaError || !tableMeta) {
console.error("Table not found or load error:", metaError);
return NextResponse.json({ error: "Table not found" }, { status: 404 });
}
const updatePayload: Record<string, unknown> = {
updated_by: user.id,
last_synced_at: new Date().toISOString(),
};
if (body?.title !== undefined) {
updatePayload.title = body.title;
}
if (body?.schema) {
updatePayload.schema = body.schema;
}
if (body?.snapshot !== undefined) {
updatePayload.snapshot = body.snapshot ?? {};
}
if (body?.viewPreferences) {
updatePayload.view_preferences = body.viewPreferences;
}
const { error: updateError } = await supabase
.from("document_tables")
.update(updatePayload)
.eq("id", tableId);
if (updateError) {
console.error("Failed to update table:", updateError);
return NextResponse.json({ error: "Failed to update table", details: updateError.message }, { status: 500 });
}
const nextRows = body?.rows ?? body?.snapshot?.rows ?? [];
if (Array.isArray(nextRows)) {
const { error: deleteRowsError } = await supabase
.from("document_table_rows")
.delete()
.eq("table_id", tableId);
if (deleteRowsError) {
console.error("Failed to clear old rows:", deleteRowsError);
return NextResponse.json({ error: "Failed to update rows", details: deleteRowsError.message }, { status: 500 });
}
const sanitizedRows = nextRows
.filter((row) => row && typeof row === "object" && Object.keys(row).length > 0);
if (sanitizedRows.length > 0) {
const rowsToInsert = sanitizedRows.map((row, index) => ({
table_id: tableId,
workspace_id: tableMeta.workspace_id,
document_id: tableMeta.document_id,
row_index: index,
row_data: row,
row_hash: null,
is_deleted: false,
updated_by: user.id,
}));
const { error: insertError } = await supabase
.from("document_table_rows")
.insert(rowsToInsert);
if (insertError) {
console.error("Failed to insert rows:", insertError);
return NextResponse.json({ error: "Failed to insert rows", details: insertError.message }, { status: 500 });
}
}
}
const { data: latest, error: fetchError } = await supabase
.from("document_tables")
.select("*")
.eq("id", tableId)
.single();
if (fetchError || !latest) {
console.error("Failed to fetch updated table:", fetchError);
return NextResponse.json({ error: "Failed to load updated table", details: fetchError?.message }, { status: 500 });
}
return NextResponse.json(latest, { status: 200 });
} catch (error) {
console.error("API error:", error);
const message = error instanceof Error ? error.message : "Internal Server Error";
return NextResponse.json({ error: message }, { status: 500 });
}
return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });
}
export async function DELETE(request: Request, context: RouteContext) {
export async function DELETE(_request: Request, context: RouteContext) {
const tableId = await extractTableId(context);
if (!tableId) {
return NextResponse.json({ error: "Missing tableId" }, { status: 400 });
}
// Convex 模式
if (isConvexEnabled()) {
const { auth, client } = await getAuthedConvexClient();
try {
@@ -264,37 +115,6 @@ export async function DELETE(request: Request, context: RouteContext) {
}
}
// Supabase 模式
const { supabase, user } = await getAuthUser();
if (!user) {
return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
}
try {
const { error: deleteRowsError } = await supabase
.from("document_table_rows")
.delete()
.eq("table_id", tableId);
if (deleteRowsError) {
console.error("Failed to delete table rows:", deleteRowsError);
return NextResponse.json({ error: "Failed to delete table rows" }, { status: 500 });
}
const { error: deleteTableError } = await supabase
.from("document_tables")
.delete()
.eq("id", tableId);
if (deleteTableError) {
console.error("Failed to delete table:", deleteTableError);
return NextResponse.json({ error: "Failed to delete table" }, { status: 500 });
}
return NextResponse.json({ success: true }, { status: 200 });
} catch (error) {
console.error("API error:", error);
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });
}
@@ -1,5 +1,4 @@
import { NextResponse } from "next/server";
import { createSupabaseRouteClient } from "@/lib/supabase/server";
import { DocumentTableSnapshot, TableSchema } from "@/types/online-table";
import { isConvexEnabled } from "@/lib/convex/enabled";
import { getAuthedConvexClient } from "@/lib/convex/route";
@@ -27,7 +26,6 @@ export async function POST(request: Request) {
// 获取 document 所在的 workspace_id
const document = await client.query(api.documents.getMeta, {
userId: auth.userId,
id: documentId,
});
@@ -54,6 +52,9 @@ export async function POST(request: Request) {
}
// Supabase 模式
return NextResponse.json({ error: "当前仅支持 Convex 模式" }, { status: 501 });
/*
const supabase = await createSupabaseRouteClient();
const { data: { user } } = await supabase.auth.getUser();
@@ -112,4 +113,5 @@ export async function POST(request: Request) {
console.error("API error:", error);
return NextResponse.json({ error: "Internal Server Error" }, { status: 500 });
}
*/
}