feat: Implement a new dashboard layout with sidebar, introduce project and data source management, and add various UI components.

This commit is contained in:
2026-02-03 15:11:53 +00:00
parent a795e92ef3
commit 7e3854d7d6
29 changed files with 2460 additions and 645 deletions

70
convex/projects.ts Normal file
View File

@@ -0,0 +1,70 @@
import { mutation, query } from "./_generated/server";
import { v } from "convex/values";
import { getAuthUserId } from "@convex-dev/auth/server";
export const getProjects = query({
args: {},
handler: async (ctx) => {
const userId = await getAuthUserId(ctx);
if (!userId) return [];
return await ctx.db
.query("projects")
.withIndex("by_owner", (q) => q.eq("userId", userId)) // Note: Need to add index to schema too? Or just filter? Schema doesn't define indexes yet. Will rely on filter for now or filter in memory if small. Actually, will rely on simple filter or add index later.
.filter((q) => q.eq(q.field("userId"), userId))
.collect();
},
});
export const getDefaultProject = query({
args: {},
handler: async (ctx) => {
const userId = await getAuthUserId(ctx);
if (!userId) return null;
return await ctx.db
.query("projects")
.filter((q) => q.and(q.eq(q.field("userId"), userId), q.eq(q.field("isDefault"), true)))
.first();
},
});
export const createProject = mutation({
args: { name: v.string(), isDefault: v.boolean() },
handler: async (ctx, args) => {
const userId = await getAuthUserId(ctx);
if (!userId) throw new Error("Unauthorized");
// If setting as default, unset other defaults? For now assume handled by UI or logic
// Actually simplicity: just create.
return await ctx.db.insert("projects", {
userId,
name: args.name,
isDefault: args.isDefault,
dorkingConfig: { selectedSourceIds: [] },
});
},
});
export const toggleDataSourceConfig = mutation({
args: { projectId: v.id("projects"), sourceId: v.id("dataSources"), selected: v.boolean() },
handler: async (ctx, args) => {
const userId = await getAuthUserId(ctx);
if (!userId) throw new Error("Unauthorized");
const project = await ctx.db.get(args.projectId);
if (!project || project.userId !== userId) throw new Error("Project not found or unauthorized");
let newSelectedIds = project.dorkingConfig.selectedSourceIds;
if (args.selected) {
if (!newSelectedIds.includes(args.sourceId)) {
newSelectedIds.push(args.sourceId);
}
} else {
newSelectedIds = newSelectedIds.filter((id) => id !== args.sourceId);
}
await ctx.db.patch(args.projectId, {
dorkingConfig: { selectedSourceIds: newSelectedIds },
});
},
});