diff options
| -rw-r--r-- | apps/web/app/(canvas)/canvas/[id]/page.tsx | 4 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/canvas/layout.tsx | 13 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/canvas/page.tsx | 22 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/canvas/search&create.tsx | 35 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/canvas/thinkPad.tsx | 36 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/canvas/thinkPads.tsx | 30 | ||||
| -rw-r--r-- | apps/web/app/(canvas)/layout.tsx | 19 | ||||
| -rw-r--r-- | apps/web/app/actions/doers.ts | 35 | ||||
| -rw-r--r-- | apps/web/app/actions/fetchers.ts | 24 | ||||
| -rw-r--r-- | apps/web/cf-env.d.ts | 6 | ||||
| -rw-r--r-- | apps/web/migrations/0000_bitter_electro.sql (renamed from apps/web/migrations/000_setup.sql) | 18 | ||||
| -rw-r--r-- | apps/web/migrations/0001_remarkable_avengers.sql | 4 | ||||
| -rw-r--r-- | apps/web/migrations/meta/0000_snapshot.json | 824 | ||||
| -rw-r--r-- | apps/web/migrations/meta/_journal.json | 13 | ||||
| -rw-r--r-- | apps/web/server/db/schema.ts | 19 | ||||
| -rw-r--r-- | package.json | 2 |
16 files changed, 1076 insertions, 28 deletions
diff --git a/apps/web/app/(canvas)/canvas/[id]/page.tsx b/apps/web/app/(canvas)/canvas/[id]/page.tsx index 6efb6cf4..e58ab35e 100644 --- a/apps/web/app/(canvas)/canvas/[id]/page.tsx +++ b/apps/web/app/(canvas)/canvas/[id]/page.tsx @@ -9,15 +9,11 @@ import { AutocompleteIcon, blockIcon } from "@repo/ui/icons"; import Image from "next/image"; import { Switch } from "@repo/ui/shadcn/switch"; import { Label } from "@repo/ui/shadcn/label"; -import { useRouter } from "next/router"; function page() { const [fullScreen, setFullScreen] = useState(false); const [visible, setVisible] = useState(true); - const router = useRouter(); - router.push("/home"); - return ( <div className={`h-screen w-full ${!fullScreen ? "px-4 py-6" : "bg-[#1F2428]"} transition-all`} diff --git a/apps/web/app/(canvas)/canvas/layout.tsx b/apps/web/app/(canvas)/canvas/layout.tsx deleted file mode 100644 index 9bc3b6d7..00000000 --- a/apps/web/app/(canvas)/canvas/layout.tsx +++ /dev/null @@ -1,13 +0,0 @@ -import "../canvasStyles.css"; - -export default function RootLayout({ - children, -}: { - children: React.ReactNode; -}) { - return ( - <div lang="en" className="bg-[#151515]"> - <div>{children}</div> - </div> - ); -} diff --git a/apps/web/app/(canvas)/canvas/page.tsx b/apps/web/app/(canvas)/canvas/page.tsx index 8b5252af..815d0b93 100644 --- a/apps/web/app/(canvas)/canvas/page.tsx +++ b/apps/web/app/(canvas)/canvas/page.tsx @@ -1,9 +1,23 @@ -import { redirect } from "next/navigation"; import React from "react"; +import { getCanvas } from "@/app/actions/fetchers"; +import SearchandCreate from "./search&create"; +import ThinkPads from "./thinkPads"; -function page() { - redirect("/signin"); - return <div>page</div>; +async function page() { + const canvas = await getCanvas(); + return ( + <div className="h-screen w-full bg-[#171B1F] py-32 text-[#FFFFFF] "> + <div className="flex w-full flex-col items-center gap-8"> + <h1 className="text-4xl font-medium">Your thinkpads</h1> + <p>{JSON.stringify(canvas)}</p> + <SearchandCreate /> + { + // @ts-ignore + canvas.success && <ThinkPads data={canvas.data} /> + } + </div> + </div> + ); } export default page; diff --git a/apps/web/app/(canvas)/canvas/search&create.tsx b/apps/web/app/(canvas)/canvas/search&create.tsx new file mode 100644 index 00000000..3998dde7 --- /dev/null +++ b/apps/web/app/(canvas)/canvas/search&create.tsx @@ -0,0 +1,35 @@ +"use client" + +import { useFormStatus } from "react-dom"; +import Image from "next/image"; +import { SearchIcon } from "@repo/ui/icons"; +import { createCanvas } from "@/app/actions/doers"; + +export default function SearchandCreate() { + return ( + <div className="flex w-[90%] max-w-2xl gap-2"> + <div className="flex flex-grow items-center overflow-hidden rounded-xl bg-[#1F2428]"> + <input + placeholder="search here..." + className="flex-grow bg-[#1F2428] px-5 py-3 text-xl focus:border-none focus:outline-none" + /> + <button className="h-full border-l-2 border-[#384149] px-2 pl-2"> + <Image src={SearchIcon} alt="search" /> + </button> + </div> + + <form action={createCanvas}> + <Button /> + </form> + </div> + ); +} + +function Button() { + const {pending} = useFormStatus() + return ( + <button className="rounded-xl bg-[#1F2428] px-5 py-3 text-xl text-[#B8C4C6]"> + {pending? "Creating.." : "Create New"} + </button> + ); +}
\ No newline at end of file diff --git a/apps/web/app/(canvas)/canvas/thinkPad.tsx b/apps/web/app/(canvas)/canvas/thinkPad.tsx new file mode 100644 index 00000000..dad2de48 --- /dev/null +++ b/apps/web/app/(canvas)/canvas/thinkPad.tsx @@ -0,0 +1,36 @@ +import {motion} from "framer-motion" +import Link from "next/link"; + +const childVariants = { + hidden: { opacity: 0, y: 10, filter: "blur(2px)" }, + visible: { opacity: 1, y: 0, filter: "blur(0px)" }, +}; + +export default function ThinkPad({ + title, + description, + image, + id +}: { + title: string; + description: string; + image: string; + id: string; +}) { + return ( + <motion.div + variants={childVariants} + className="flex h-48 gap-4 rounded-2xl bg-[#1F2428] p-2" + > + <Link className="h-full min-w-[40%] rounded-xl bg-[#363f46]" href={`/canvas/${id}`}> + <div></div> + </Link> + <div className="flex flex-col gap-2"> + <div>{title}</div> + <div className="overflow-hidden text-ellipsis text-[#B8C4C6]"> + {description} + </div> + </div> + </motion.div> + ); +}
\ No newline at end of file diff --git a/apps/web/app/(canvas)/canvas/thinkPads.tsx b/apps/web/app/(canvas)/canvas/thinkPads.tsx new file mode 100644 index 00000000..b83d4142 --- /dev/null +++ b/apps/web/app/(canvas)/canvas/thinkPads.tsx @@ -0,0 +1,30 @@ +"use client"; +import { motion } from "framer-motion"; +import ThinkPad from "./thinkPad"; + +const containerVariants = { + hidden: { opacity: 0 }, + visible: { + opacity: 1, + transition: { + staggerChildren: 0.1, + }, + }, +}; + +export default function ThinkPads({data}: { + data: {image: string, title:string, description:string, id: string}[] +}) { + return ( + <motion.div + variants={containerVariants} + initial="hidden" + animate="visible" + className="w-[90%] max-w-2xl space-y-6" + > + {data.map((item) => { + return <ThinkPad {...item} />; + })} + </motion.div> + ); +} diff --git a/apps/web/app/(canvas)/layout.tsx b/apps/web/app/(canvas)/layout.tsx new file mode 100644 index 00000000..5c925573 --- /dev/null +++ b/apps/web/app/(canvas)/layout.tsx @@ -0,0 +1,19 @@ +import { auth } from "@/server/auth"; +import "./canvasStyles.css"; +import { redirect } from "next/navigation"; + +export default async function RootLayout({ + children, +}: { + children: React.ReactNode; +}) { + + const info = await auth(); + + if (!info) { + return redirect("/signin"); + } + return ( + <div>{children}</div> + ); +} diff --git a/apps/web/app/actions/doers.ts b/apps/web/app/actions/doers.ts index 99a1b719..30ddbc8e 100644 --- a/apps/web/app/actions/doers.ts +++ b/apps/web/app/actions/doers.ts @@ -3,6 +3,7 @@ import { revalidatePath } from "next/cache"; import { db } from "../../server/db"; import { + canvas, chatHistory, chatThreads, contentToSpace, @@ -381,3 +382,37 @@ export const linkTelegramToUser = async ( data: true, }; }; + +export const createCanvas = async () => { + const data = await auth(); + + if (!data || !data.user || !data.user.id) { + redirect("/signin"); + return { error: "Not authenticated", success: false }; + } + + const resp = await db + .insert(canvas) + .values({ userId: data.user.id }).returning({id: canvas.id}); + redirect(`/canvas/${resp[0]!.id}`); + // TODO INVESTIGATE: NO REDIRECT INSIDE TRY CATCH BLOCK + // try { + // const resp = await db + // .insert(canvas) + // .values({ userId: data.user.id }).returning({id: canvas.id}); + // return redirect(`/canvas/${resp[0]!.id}`); + // } catch (e: unknown) { + // const error = e as Error; + // if ( + // error.message.includes("D1_ERROR: UNIQUE constraint failed: space.name") + // ) { + // return { success: false, data: 0, error: "Space already exists" }; + // } else { + // return { + // success: false, + // data: 0, + // error: "Failed to create space with error: " + error.message, + // }; + // } + // } +};
\ No newline at end of file diff --git a/apps/web/app/actions/fetchers.ts b/apps/web/app/actions/fetchers.ts index 664c20ac..f485c28d 100644 --- a/apps/web/app/actions/fetchers.ts +++ b/apps/web/app/actions/fetchers.ts @@ -3,6 +3,7 @@ import { and, asc, eq, inArray, not, sql } from "drizzle-orm"; import { db } from "../../server/db"; import { + canvas, chatHistory, ChatThread, chatThreads, @@ -189,3 +190,26 @@ export const getChatHistory = async (): ServerActionReturnType< }; } }; + +export const getCanvas = async () => { + const data = await auth(); + + if (!data || !data.user || !data.user.id) { + redirect("/signin"); + return { error: "Not authenticated", success: false }; + } + + try { + const canvases = await db.select().from(canvas).where(eq(canvas.userId, data.user.id)) + + return { + success: true, + data: canvases.map(({ userId, ...rest }) => rest), + }; + } catch (e) { + return { + success: false, + error: (e as Error).message, + }; + } +}; diff --git a/apps/web/cf-env.d.ts b/apps/web/cf-env.d.ts index be5c991a..e645f7b1 100644 --- a/apps/web/cf-env.d.ts +++ b/apps/web/cf-env.d.ts @@ -4,13 +4,19 @@ declare global { GOOGLE_CLIENT_ID: string; GOOGLE_CLIENT_SECRET: string; AUTH_SECRET: string; + R2_ENDPOINT: string; R2_ACCESS_KEY_ID: string; R2_SECRET_ACCESS_KEY: string; R2_PUBLIC_BUCKET_ADDRESS: string; R2_BUCKET_NAME: string; + BACKEND_SECURITY_KEY: string; BACKEND_BASE_URL: string; + + CLOUDFLARE_ACCOUNT_ID: string, + CLOUDFLARE_DATABASE_ID: string, + CLOUDFLARE_D1_TOKEN: string, } } } diff --git a/apps/web/migrations/000_setup.sql b/apps/web/migrations/0000_bitter_electro.sql index a4855ec9..3ce840e7 100644 --- a/apps/web/migrations/000_setup.sql +++ b/apps/web/migrations/0000_bitter_electro.sql @@ -27,6 +27,15 @@ CREATE TABLE `authenticator` ( FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade ); --> statement-breakpoint +CREATE TABLE `canvas` ( + `id` text PRIMARY KEY NOT NULL, + `title` text DEFAULT 'Untitled' NOT NULL, + `description` text DEFAULT 'Untitled' NOT NULL, + `url` text DEFAULT '' NOT NULL, + `userId` text NOT NULL, + FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE cascade +); +--> statement-breakpoint CREATE TABLE `chatHistory` ( `id` integer PRIMARY KEY AUTOINCREMENT NOT NULL, `threadId` text NOT NULL, @@ -86,7 +95,8 @@ CREATE TABLE `user` ( `name` text, `email` text NOT NULL, `emailVerified` integer, - `image` text + `image` text, + `telegramId` text ); --> statement-breakpoint CREATE TABLE `verificationToken` ( @@ -97,6 +107,7 @@ CREATE TABLE `verificationToken` ( ); --> statement-breakpoint CREATE UNIQUE INDEX `authenticator_credentialID_unique` ON `authenticator` (`credentialID`);--> statement-breakpoint +CREATE INDEX `canvas_user_userId` ON `canvas` (`userId`);--> statement-breakpoint CREATE INDEX `chatHistory_thread_idx` ON `chatHistory` (`threadId`);--> statement-breakpoint CREATE INDEX `chatThread_user_idx` ON `chatThread` (`userId`);--> statement-breakpoint CREATE UNIQUE INDEX `space_name_unique` ON `space` (`name`);--> statement-breakpoint @@ -105,4 +116,7 @@ CREATE INDEX `spaces_user_idx` ON `space` (`user`);--> statement-breakpoint CREATE INDEX `storedContent_url_idx` ON `storedContent` (`url`);--> statement-breakpoint CREATE INDEX `storedContent_savedAt_idx` ON `storedContent` (`savedAt`);--> statement-breakpoint CREATE INDEX `storedContent_title_idx` ON `storedContent` (`title`);--> statement-breakpoint -CREATE INDEX `storedContent_user_idx` ON `storedContent` (`user`); +CREATE INDEX `storedContent_user_idx` ON `storedContent` (`user`);--> statement-breakpoint +CREATE INDEX `users_email_idx` ON `user` (`email`);--> statement-breakpoint +CREATE INDEX `users_telegram_idx` ON `user` (`telegramId`);--> statement-breakpoint +CREATE INDEX `users_id_idx` ON `user` (`id`);
\ No newline at end of file diff --git a/apps/web/migrations/0001_remarkable_avengers.sql b/apps/web/migrations/0001_remarkable_avengers.sql deleted file mode 100644 index cb2fa422..00000000 --- a/apps/web/migrations/0001_remarkable_avengers.sql +++ /dev/null @@ -1,4 +0,0 @@ -ALTER TABLE `user` ADD `telegramId` text;--> statement-breakpoint -CREATE INDEX `users_email_idx` ON `user` (`email`);--> statement-breakpoint -CREATE INDEX `users_telegram_idx` ON `user` (`telegramId`);--> statement-breakpoint -CREATE INDEX `users_id_idx` ON `user` (`id`);
\ No newline at end of file diff --git a/apps/web/migrations/meta/0000_snapshot.json b/apps/web/migrations/meta/0000_snapshot.json new file mode 100644 index 00000000..30920063 --- /dev/null +++ b/apps/web/migrations/meta/0000_snapshot.json @@ -0,0 +1,824 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "58ec8bd8-5aad-4ade-a718-74eaf6056d36", + "prevId": "00000000-0000-0000-0000-000000000000", + "tables": { + "account": { + "name": "account", + "columns": { + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider": { + "name": "provider", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "session_state": { + "name": "session_state", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_userId_user_id_fk": { + "name": "account_userId_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "account_provider_providerAccountId_pk": { + "columns": [ + "provider", + "providerAccountId" + ], + "name": "account_provider_providerAccountId_pk" + } + }, + "uniqueConstraints": {} + }, + "authenticator": { + "name": "authenticator", + "columns": { + "credentialID": { + "name": "credentialID", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "providerAccountId": { + "name": "providerAccountId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialPublicKey": { + "name": "credentialPublicKey", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "counter": { + "name": "counter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialDeviceType": { + "name": "credentialDeviceType", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "credentialBackedUp": { + "name": "credentialBackedUp", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "transports": { + "name": "transports", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "authenticator_credentialID_unique": { + "name": "authenticator_credentialID_unique", + "columns": [ + "credentialID" + ], + "isUnique": true + } + }, + "foreignKeys": { + "authenticator_userId_user_id_fk": { + "name": "authenticator_userId_user_id_fk", + "tableFrom": "authenticator", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "authenticator_userId_credentialID_pk": { + "columns": [ + "credentialID", + "userId" + ], + "name": "authenticator_userId_credentialID_pk" + } + }, + "uniqueConstraints": {} + }, + "canvas": { + "name": "canvas", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'Untitled'" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "''" + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "canvas_user_userId": { + "name": "canvas_user_userId", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "canvas_userId_user_id_fk": { + "name": "canvas_userId_user_id_fk", + "tableFrom": "canvas", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatHistory": { + "name": "chatHistory", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "threadId": { + "name": "threadId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "question": { + "name": "question", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "answerParts": { + "name": "answerParts", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerSources": { + "name": "answerSources", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "answerJustification": { + "name": "answerJustification", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "chatHistory_thread_idx": { + "name": "chatHistory_thread_idx", + "columns": [ + "threadId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "chatHistory_threadId_chatThread_id_fk": { + "name": "chatHistory_threadId_chatThread_id_fk", + "tableFrom": "chatHistory", + "tableTo": "chatThread", + "columnsFrom": [ + "threadId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "chatThread": { + "name": "chatThread", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "firstMessage": { + "name": "firstMessage", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "chatThread_user_idx": { + "name": "chatThread_user_idx", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "chatThread_userId_user_id_fk": { + "name": "chatThread_userId_user_id_fk", + "tableFrom": "chatThread", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "contentToSpace": { + "name": "contentToSpace", + "columns": { + "contentId": { + "name": "contentId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "spaceId": { + "name": "spaceId", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "contentToSpace_contentId_storedContent_id_fk": { + "name": "contentToSpace_contentId_storedContent_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "storedContent", + "columnsFrom": [ + "contentId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "contentToSpace_spaceId_space_id_fk": { + "name": "contentToSpace_spaceId_space_id_fk", + "tableFrom": "contentToSpace", + "tableTo": "space", + "columnsFrom": [ + "spaceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "contentToSpace_contentId_spaceId_pk": { + "columns": [ + "contentId", + "spaceId" + ], + "name": "contentToSpace_contentId_spaceId_pk" + } + }, + "uniqueConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "sessionToken": { + "name": "sessionToken", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "userId": { + "name": "userId", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "session_userId_user_id_fk": { + "name": "session_userId_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "space": { + "name": "space", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'none'" + }, + "user": { + "name": "user", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "space_name_unique": { + "name": "space_name_unique", + "columns": [ + "name" + ], + "isUnique": true + }, + "spaces_name_idx": { + "name": "spaces_name_idx", + "columns": [ + "name" + ], + "isUnique": false + }, + "spaces_user_idx": { + "name": "spaces_user_idx", + "columns": [ + "user" + ], + "isUnique": false + } + }, + "foreignKeys": { + "space_user_user_id_fk": { + "name": "space_user_user_id_fk", + "tableFrom": "space", + "tableTo": "user", + "columnsFrom": [ + "user" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "storedContent": { + "name": "storedContent", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "savedAt": { + "name": "savedAt", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "baseUrl": { + "name": "baseUrl", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ogImage": { + "name": "ogImage", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'page'" + }, + "image": { + "name": "image", + "type": "text(255)", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user": { + "name": "user", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "storedContent_url_idx": { + "name": "storedContent_url_idx", + "columns": [ + "url" + ], + "isUnique": false + }, + "storedContent_savedAt_idx": { + "name": "storedContent_savedAt_idx", + "columns": [ + "savedAt" + ], + "isUnique": false + }, + "storedContent_title_idx": { + "name": "storedContent_title_idx", + "columns": [ + "title" + ], + "isUnique": false + }, + "storedContent_user_idx": { + "name": "storedContent_user_idx", + "columns": [ + "user" + ], + "isUnique": false + } + }, + "foreignKeys": { + "storedContent_user_user_id_fk": { + "name": "storedContent_user_user_id_fk", + "tableFrom": "storedContent", + "tableTo": "user", + "columnsFrom": [ + "user" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "emailVerified": { + "name": "emailVerified", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "telegramId": { + "name": "telegramId", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "users_email_idx": { + "name": "users_email_idx", + "columns": [ + "email" + ], + "isUnique": false + }, + "users_telegram_idx": { + "name": "users_telegram_idx", + "columns": [ + "telegramId" + ], + "isUnique": false + }, + "users_id_idx": { + "name": "users_id_idx", + "columns": [ + "id" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "verificationToken": { + "name": "verificationToken", + "columns": { + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires": { + "name": "expires", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": { + "verificationToken_identifier_token_pk": { + "columns": [ + "identifier", + "token" + ], + "name": "verificationToken_identifier_token_pk" + } + }, + "uniqueConstraints": {} + } + }, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": {} + } +}
\ No newline at end of file diff --git a/apps/web/migrations/meta/_journal.json b/apps/web/migrations/meta/_journal.json new file mode 100644 index 00000000..68c578aa --- /dev/null +++ b/apps/web/migrations/meta/_journal.json @@ -0,0 +1,13 @@ +{ + "version": "7", + "dialect": "sqlite", + "entries": [ + { + "idx": 0, + "version": "6", + "when": 1719619409551, + "tag": "0000_bitter_electro", + "breakpoints": true + } + ] +}
\ No newline at end of file diff --git a/apps/web/server/db/schema.ts b/apps/web/server/db/schema.ts index 69372a35..c40e50f1 100644 --- a/apps/web/server/db/schema.ts +++ b/apps/web/server/db/schema.ts @@ -198,5 +198,24 @@ export const chatHistory = createTable( }), ); +export const canvas = createTable( + "canvas", + { + id: text("id") + .notNull() + .primaryKey() + .$defaultFn(() => crypto.randomUUID()), + title: text("title").default("Untitled").notNull(), + description: text("description").default("Untitled").notNull(), + imageUrl: text("url").default("").notNull(), + userId: text("userId") + .notNull() + .references(() => users.id, { onDelete: "cascade" }), + }, + (canvas) => ({ + userIdx: index("canvas_user_userId").on(canvas.userId), + }), +); + export type ChatThread = typeof chatThreads.$inferSelect; export type ChatHistory = typeof chatHistory.$inferSelect; diff --git a/package.json b/package.json index c94610a6..e95e630c 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "@repo/ui": "*", "@tailwindcss/typography": "^0.5.13", "autoprefixer": "^10.4.19", - "drizzle-kit": "^0.21.2", + "drizzle-kit": "^0.22.7", "eslint-plugin-next-on-pages": "^1.11.3", "lint-staged": "^15.2.5", "postcss": "^8.4.38", |