chore: release 0.0.1
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
import { NextResponse } from "next/server";
|
||||
import type { NextRequest } from "next/server";
|
||||
import { createSupabaseRouteClient } from "@/lib/supabase/server";
|
||||
|
||||
export async function POST(request: NextRequest) {
|
||||
const supabase = await createSupabaseRouteClient();
|
||||
const { event, session } = await request.json();
|
||||
|
||||
if (event === "SIGNED_IN" || event === "TOKEN_REFRESHED") {
|
||||
await supabase.auth.setSession(session);
|
||||
}
|
||||
|
||||
if (event === "SIGNED_OUT") {
|
||||
await supabase.auth.signOut();
|
||||
}
|
||||
|
||||
return NextResponse.json({ success: true });
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
"use server";
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
import { createSupabaseRouteClient } from "@/lib/supabase/server";
|
||||
|
||||
export async function GET(request: Request) {
|
||||
const url = new URL(request.url);
|
||||
const gridKey = url.searchParams.get("gridKey");
|
||||
|
||||
if (!gridKey) {
|
||||
return NextResponse.json({ code: 400, msg: "gridKey 参数缺失" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabase = await createSupabaseRouteClient();
|
||||
const { data, error } = await supabase
|
||||
.from("document_tables")
|
||||
.select("id,title,grid_key")
|
||||
.eq("grid_key", gridKey)
|
||||
.single();
|
||||
|
||||
if (error || !data) {
|
||||
return NextResponse.json({ code: 404, msg: "未查询到相关数据" }, { status: 404 });
|
||||
}
|
||||
|
||||
return NextResponse.json({
|
||||
code: 200,
|
||||
msg: "ok",
|
||||
data: {
|
||||
title: data.title ?? "未命名工作簿",
|
||||
lang: "zh",
|
||||
gridKey: data.grid_key,
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
"use server";
|
||||
|
||||
import { NextResponse } from "next/server";
|
||||
import { createDefaultTableSnapshot } from "@/lib/online-table";
|
||||
import { createSupabaseRouteClient } from "@/lib/supabase/server";
|
||||
import type { DocumentTableSnapshot, TableSchema } from "@/types/online-table";
|
||||
|
||||
const fallbackSchema: TableSchema = {
|
||||
columns: [],
|
||||
frozenRowCount: 0,
|
||||
frozenColCount: 0,
|
||||
};
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const url = new URL(request.url);
|
||||
const gridKey = url.searchParams.get("gridKey");
|
||||
|
||||
if (!gridKey) {
|
||||
return NextResponse.json({ code: 400, msg: "gridKey 参数缺失" }, { status: 400 });
|
||||
}
|
||||
|
||||
const supabase = await createSupabaseRouteClient();
|
||||
const { data, error } = await supabase
|
||||
.from("document_tables")
|
||||
.select("schema,snapshot")
|
||||
.eq("grid_key", gridKey)
|
||||
.single();
|
||||
|
||||
if (error || !data) {
|
||||
return NextResponse.json({ code: 404, msg: "未查询到相关数据" }, { status: 404 });
|
||||
}
|
||||
|
||||
const snapshot = (data.snapshot as DocumentTableSnapshot | null) ?? null;
|
||||
const schema = (data.schema as TableSchema | null) ?? fallbackSchema;
|
||||
|
||||
let payload: unknown[] = [];
|
||||
if (snapshot?.luckysheet && Array.isArray(snapshot.luckysheet)) {
|
||||
payload = snapshot.luckysheet;
|
||||
} else {
|
||||
const defaultSnapshot = createDefaultTableSnapshot(schema);
|
||||
payload = defaultSnapshot.luckysheet ?? [];
|
||||
}
|
||||
|
||||
const body = JSON.stringify(payload);
|
||||
return new NextResponse(body, {
|
||||
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
"use server";
|
||||
|
||||
import { Buffer } from "node:buffer";
|
||||
import { randomUUID } from "node:crypto";
|
||||
import { NextResponse } from "next/server";
|
||||
import { createSupabaseRouteClient } from "@/lib/supabase/server";
|
||||
|
||||
const BUCKET = "media";
|
||||
const DIRECTORY = "luckysheet";
|
||||
|
||||
export async function POST(request: Request) {
|
||||
const supabase = await createSupabaseRouteClient();
|
||||
const formData = await request.formData();
|
||||
const file = formData.get("image");
|
||||
|
||||
if (!(file instanceof File)) {
|
||||
return NextResponse.json({ code: 400, msg: "缺少 image 文件" }, { status: 400 });
|
||||
}
|
||||
|
||||
const arrayBuffer = await file.arrayBuffer();
|
||||
const buffer = Buffer.from(arrayBuffer);
|
||||
const extension = file.name?.split(".").pop() || "bin";
|
||||
const objectPath = `${DIRECTORY}/${randomUUID()}.${extension}`;
|
||||
|
||||
const { error: uploadError } = await supabase.storage
|
||||
.from(BUCKET)
|
||||
.upload(objectPath, buffer, { contentType: file.type || "application/octet-stream", upsert: false });
|
||||
|
||||
if (uploadError) {
|
||||
return NextResponse.json({ code: 500, msg: "上传失败", detail: uploadError.message }, { status: 500 });
|
||||
}
|
||||
|
||||
const {
|
||||
data: { publicUrl },
|
||||
} = supabase.storage.from(BUCKET).getPublicUrl(objectPath);
|
||||
|
||||
return NextResponse.json({
|
||||
code: 200,
|
||||
msg: "ok",
|
||||
url: publicUrl,
|
||||
});
|
||||
}
|
||||
@@ -98,7 +98,7 @@ export async function PATCH(request: Request, context: RouteContext) {
|
||||
try {
|
||||
const { data: tableMeta, error: metaError } = await supabase
|
||||
.from("document_tables")
|
||||
.select("id, workspace_id, document_id")
|
||||
.select("id, workspace_id, document_id, grid_key")
|
||||
.eq("id", tableId)
|
||||
.single();
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { redirect } from "next/navigation";
|
||||
import { createSupabaseServerClient } from "@/lib/supabase/server";
|
||||
import { ensureDefaultWorkspace, resolveActiveWorkspaceId } from "@/lib/workspaces";
|
||||
|
||||
export default async function Home() {
|
||||
const supabase = await createSupabaseServerClient();
|
||||
@@ -11,10 +12,18 @@ export default async function Home() {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
await ensureDefaultWorkspace(supabase, session.user.id, session.user.email ?? "我的空间");
|
||||
const workspaceId = await resolveActiveWorkspaceId(supabase, session.user.id);
|
||||
|
||||
if (!workspaceId) {
|
||||
redirect("/login");
|
||||
}
|
||||
|
||||
const { data: firstDoc } = await supabase
|
||||
.from("documents")
|
||||
.select("id")
|
||||
.eq("user_id", session.user.id)
|
||||
.eq("workspace_id", workspaceId)
|
||||
.order("created_at", { ascending: true })
|
||||
.limit(1)
|
||||
.maybeSingle();
|
||||
@@ -27,6 +36,7 @@ export default async function Home() {
|
||||
.from("documents")
|
||||
.insert({
|
||||
user_id: session.user.id,
|
||||
workspace_id: workspaceId,
|
||||
title: "新页面",
|
||||
content: {},
|
||||
})
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import HeadlessTableViewer from "@/components/online-table/HeadlessTableViewer";
|
||||
|
||||
interface TableViewerPageProps {
|
||||
params: Promise<{ tableId: string }>;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
searchParams: Promise<Record<string, any>>;
|
||||
}
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
export default async function TableViewerPage({ params, searchParams }: TableViewerPageProps) {
|
||||
const resolvedParams = await params;
|
||||
const resolvedSearch = await searchParams;
|
||||
const tableId = resolvedParams.tableId;
|
||||
const embedMode = resolvedSearch?.embed === "1";
|
||||
|
||||
return (
|
||||
<div className={embedMode ? "min-h-screen bg-transparent" : "min-h-screen bg-white"}>
|
||||
<HeadlessTableViewer tableId={tableId} embed={embedMode} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user