aboutsummaryrefslogtreecommitdiff
path: root/apps
diff options
context:
space:
mode:
authorDhravya <[email protected]>2024-04-05 18:02:00 -0700
committerDhravya <[email protected]>2024-04-05 18:02:00 -0700
commit739d7c380884ae47e4de082fbc4ef9c5d6ebe7e0 (patch)
treec557c993057ee6c51392781b68d78cbf25217782 /apps
parentmake ext work with dev mode (diff)
downloadarchived-supermemory-739d7c380884ae47e4de082fbc4ef9c5d6ebe7e0.tar.xz
archived-supermemory-739d7c380884ae47e4de082fbc4ef9c5d6ebe7e0.zip
(NEEDS MIGRATION)made sidebar functional
Diffstat (limited to 'apps')
-rw-r--r--apps/web/db/prepare.sql19
-rw-r--r--apps/web/src/app/MessagePoster.tsx11
-rw-r--r--apps/web/src/app/api/store/route.ts34
-rw-r--r--apps/web/src/app/page.tsx22
-rw-r--r--apps/web/src/components/Sidebar.tsx6
-rw-r--r--apps/web/src/components/Sidebar/CategoryItem.tsx147
-rw-r--r--apps/web/src/components/Sidebar/MemoriesBar.tsx1
-rw-r--r--apps/web/src/server/db/schema.ts20
-rw-r--r--apps/web/types/memory.tsx36
9 files changed, 184 insertions, 112 deletions
diff --git a/apps/web/db/prepare.sql b/apps/web/db/prepare.sql
index 62cba941..a4f9951d 100644
--- a/apps/web/db/prepare.sql
+++ b/apps/web/db/prepare.sql
@@ -16,6 +16,14 @@ CREATE TABLE `account` (
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
+CREATE TABLE `contentToSpace` (
+ `contentId` integer NOT NULL,
+ `spaceId` integer NOT NULL,
+ PRIMARY KEY(`contentId`, `spaceId`),
+ FOREIGN KEY (`contentId`) REFERENCES `storedContent`(`id`) ON UPDATE no action ON DELETE no action,
+ FOREIGN KEY (`spaceId`) REFERENCES `space`(`id`) ON UPDATE no action ON DELETE no action
+);
+--> statement-breakpoint
CREATE TABLE `session` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`sessionToken` text(255) NOT NULL,
@@ -24,10 +32,11 @@ CREATE TABLE `session` (
FOREIGN KEY (`userId`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
-CREATE TABLE `spaces` (
+CREATE TABLE `space` (
`id` integer PRIMARY KEY AUTOINCREMENT NOT NULL,
`name` text DEFAULT 'all' NOT NULL,
- `description` text(255)
+ `user` text(255),
+ FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
CREATE TABLE `storedContent` (
@@ -36,12 +45,10 @@ CREATE TABLE `storedContent` (
`title` text(255),
`description` text(255),
`url` text NOT NULL,
- `space` text(255) DEFAULT 'all',
`savedAt` integer NOT NULL,
`baseUrl` text(255),
`image` text(255),
`user` text(255),
- FOREIGN KEY (`space`) REFERENCES `spaces`(`name`) ON UPDATE no action ON DELETE no action,
FOREIGN KEY (`user`) REFERENCES `user`(`id`) ON UPDATE no action ON DELETE no action
);
--> statement-breakpoint
@@ -62,9 +69,9 @@ CREATE TABLE `verificationToken` (
--> statement-breakpoint
CREATE INDEX `account_userId_idx` ON `account` (`userId`);--> statement-breakpoint
CREATE INDEX `session_userId_idx` ON `session` (`userId`);--> statement-breakpoint
-CREATE INDEX `spaces_name_idx` ON `spaces` (`name`);--> statement-breakpoint
+CREATE INDEX `spaces_name_idx` ON `space` (`name`);--> statement-breakpoint
+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_space_idx` ON `storedContent` (`space`);--> statement-breakpoint
CREATE INDEX `storedContent_user_idx` ON `storedContent` (`user`); \ No newline at end of file
diff --git a/apps/web/src/app/MessagePoster.tsx b/apps/web/src/app/MessagePoster.tsx
index 3d0bbe7e..64dc89fd 100644
--- a/apps/web/src/app/MessagePoster.tsx
+++ b/apps/web/src/app/MessagePoster.tsx
@@ -8,7 +8,16 @@ function MessagePoster({ jwt }: { jwt: string }) {
window.postMessage({ jwt }, '*');
}, [jwt]);
- return null;
+ return (
+ <button
+ onClick={() => {
+ if (typeof window === 'undefined') return;
+ window.postMessage({ jwt }, '*');
+ }}
+ >
+ Send message
+ </button>
+ );
}
export default MessagePoster;
diff --git a/apps/web/src/app/api/store/route.ts b/apps/web/src/app/api/store/route.ts
index 3a4f7e27..06db08b9 100644
--- a/apps/web/src/app/api/store/route.ts
+++ b/apps/web/src/app/api/store/route.ts
@@ -1,6 +1,6 @@
import { db } from "@/server/db";
-import { eq } from "drizzle-orm";
-import { sessions, storedContent, users } from "@/server/db/schema";
+import { and, eq } from "drizzle-orm";
+import { contentToSpace, sessions, storedContent, users, space } from "@/server/db/schema";
import { type NextRequest, NextResponse } from "next/server";
import { env } from "@/env";
import { getMetaData } from "@/server/helpers";
@@ -31,6 +31,7 @@ export async function POST(req: NextRequest) {
const data = await req.json() as {
pageContent: string,
url: string,
+ space?: string
};
const metadata = await getMetaData(data.url);
@@ -38,6 +39,12 @@ export async function POST(req: NextRequest) {
let id: number | undefined = undefined;
+ let storeToSpace = data.space
+
+ if (!storeToSpace) {
+ storeToSpace = 'all'
+ }
+
const storedContentId = await db.insert(storedContent).values({
content: data.pageContent,
title: metadata.title,
@@ -46,12 +53,33 @@ export async function POST(req: NextRequest) {
baseUrl: metadata.baseUrl,
image: metadata.image,
savedAt: new Date(),
- space: "all",
user: session.user.id
})
id = storedContentId.meta.last_row_id;
+ if (!id) {
+ return NextResponse.json({ message: "Error", error: "Error in CF function" }, { status: 500 });
+ }
+
+ let spaceID = 0;
+
+ const spaceData = await db.select().from(space).where(and(eq(space.name, storeToSpace), eq(space.user, session.user.id))).limit(1)
+ spaceID = spaceData[0]?.id
+
+ if (!spaceData || spaceData.length === 0) {
+ const spaceId = await db.insert(space).values({
+ name: storeToSpace,
+ user: session.user.id
+ })
+ spaceID = spaceId.meta.last_row_id;
+ }
+
+ await db.insert(contentToSpace).values({
+ contentId: id as number,
+ spaceId: spaceID
+ })
+
const res = await Promise.race([
fetch("https://cf-ai-backend.dhravya.workers.dev/add", {
method: "POST",
diff --git a/apps/web/src/app/page.tsx b/apps/web/src/app/page.tsx
index d1d47ae5..c25de8c7 100644
--- a/apps/web/src/app/page.tsx
+++ b/apps/web/src/app/page.tsx
@@ -1,5 +1,12 @@
import { db } from '@/server/db';
-import { sessions, storedContent, users } from '@/server/db/schema';
+import {
+ contentToSpace,
+ sessions,
+ space,
+ StoredContent,
+ storedContent,
+ users,
+} from '@/server/db/schema';
import { eq, inArray } from 'drizzle-orm';
import { cookies, headers } from 'next/headers';
import { redirect } from 'next/navigation';
@@ -47,12 +54,19 @@ export default async function Home() {
return redirect('/api/auth/signin');
}
- const posts = await db
+ // Fetch all content for the user
+ const contents = await db
.select()
.from(storedContent)
- .where(eq(storedContent.user, userData.id));
+ .where(eq(storedContent.user, userData.id))
+ .all();
- const collectedSpaces = transformContent(posts);
+ console.log(contents);
+
+ const collectedSpaces =
+ contents.length > 0 ? await transformContent(contents) : [];
+
+ console.log('collected', collectedSpaces);
return (
<div className="flex w-screen">
diff --git a/apps/web/src/components/Sidebar.tsx b/apps/web/src/components/Sidebar.tsx
index 1af37025..66ca1652 100644
--- a/apps/web/src/components/Sidebar.tsx
+++ b/apps/web/src/components/Sidebar.tsx
@@ -26,8 +26,7 @@ export default function Sidebar() {
description: '',
image: 'https://code.visualstudio.com/favicon.ico',
baseUrl: 'https://code.visualstudio.com',
- savedAt: new Date(),
- space: 'Development',
+ savedAt: new Date()
},
{
id: 1,
@@ -37,8 +36,7 @@ export default function Sidebar() {
description: '',
image: 'https://github.com/favicon.ico',
baseUrl: 'https://github.com',
- savedAt: new Date(),
- space: 'Development',
+ savedAt: new Date()
},
];
diff --git a/apps/web/src/components/Sidebar/CategoryItem.tsx b/apps/web/src/components/Sidebar/CategoryItem.tsx
index c2e72ba5..0cf8a70c 100644
--- a/apps/web/src/components/Sidebar/CategoryItem.tsx
+++ b/apps/web/src/components/Sidebar/CategoryItem.tsx
@@ -1,13 +1,13 @@
-"use client";
-import { cleanUrl } from "@/lib/utils";
-import { StoredContent } from "@/server/db/schema";
+'use client';
+import { cleanUrl } from '@/lib/utils';
+import { StoredContent } from '@/server/db/schema';
import {
DropdownMenu,
DropdownMenuTrigger,
DropdownMenuContent,
DropdownMenuItem,
-} from "../ui/dropdown-menu";
-import { Label } from "../ui/label";
+} from '../ui/dropdown-menu';
+import { Label } from '../ui/label';
import {
ArrowUpRight,
MoreHorizontal,
@@ -19,8 +19,8 @@ import {
ChevronRight,
Plus,
Minus,
-} from "lucide-react";
-import { useState } from "react";
+} from 'lucide-react';
+import { useState } from 'react';
import {
Drawer,
DrawerContent,
@@ -29,116 +29,107 @@ import {
DrawerDescription,
DrawerFooter,
DrawerClose,
-} from "../ui/drawer";
-import { Input } from "../ui/input";
-import { Textarea } from "../ui/textarea";
-import { Popover, PopoverContent, PopoverTrigger } from "../ui/popover";
+} from '../ui/drawer';
+import { Input } from '../ui/input';
+import { Textarea } from '../ui/textarea';
+import { Popover, PopoverContent, PopoverTrigger } from '../ui/popover';
import {
AnimatePresence,
motion,
Reorder,
useMotionValue,
-} from "framer-motion";
+} from 'framer-motion';
const pages: StoredContent[] = [
{
id: 1,
- content: "",
- title: "Visual Studio Code",
- url: "https://code.visualstudio.com",
- description: "",
- image: "https://code.visualstudio.com/favicon.ico",
- baseUrl: "https://code.visualstudio.com",
+ content: '',
+ title: 'Visual Studio Code',
+ url: 'https://code.visualstudio.com',
+ description: '',
+ image: 'https://code.visualstudio.com/favicon.ico',
+ baseUrl: 'https://code.visualstudio.com',
savedAt: new Date(),
- space: ""
},
{
id: 2,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 3,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 4,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 5,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 6,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 7,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 8,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
{
id: 9,
- content: "",
+ content: '',
title: "yxshv/vscode: An unofficial remake of vscode's landing page",
- url: "https://github.com/yxshv/vscode",
- description: "",
- image: "https://github.com/favicon.ico",
- baseUrl: "https://github.com",
+ url: 'https://github.com/yxshv/vscode',
+ description: '',
+ image: 'https://github.com/favicon.ico',
+ baseUrl: 'https://github.com',
savedAt: new Date(),
- space: ""
},
];
export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
@@ -162,13 +153,13 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
/>
<ChevronDown
data-down-icon
- className={`absolute left-1/2 top-1/2 z-[2] h-4 w-4 min-w-4 -translate-x-1/2 -translate-y-1/2 scale-75 opacity-0 transition-[transform,opacity] duration-150 ${isExpanded ? "rotate-180" : "rotate-0"}`}
+ className={`absolute left-1/2 top-1/2 z-[2] h-4 w-4 min-w-4 -translate-x-1/2 -translate-y-1/2 scale-75 opacity-0 transition-[transform,opacity] duration-150 ${isExpanded ? 'rotate-180' : 'rotate-0'}`}
strokeWidth={1.5}
/>
</div>
<span className="w-full truncate text-nowrap text-left">
- {item.title ?? "Untitled website"}
+ {item.title ?? 'Untitled website'}
</span>
</button>
<Drawer
@@ -187,7 +178,7 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
href={item.url}
className="text-rgray-11/90 bg-rgray-3 text-md absolute right-0 top-0 flex w-min translate-y-1/2 items-center justify-center gap-1 rounded-full px-5 py-1"
>
- <img src={item.image ?? "/brain.png"} className="h-4 w-4" />
+ <img src={item.image ?? '/brain.png'} className="h-4 w-4" />
{cleanUrl(item.url)}
</a>
</DrawerHeader>
@@ -197,16 +188,16 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
<Input
className=""
required
- value={item.title ?? ""}
- placeholder={item.title ?? "Enter the title for the page"}
+ value={item.title ?? ''}
+ placeholder={item.title ?? 'Enter the title for the page'}
/>
</div>
<div className="mt-5">
<Label>Additional Context</Label>
<Textarea
className=""
- value={item.content ?? ""}
- placeholder={"Enter additional context for this page"}
+ value={item.content ?? ''}
+ placeholder={'Enter additional context for this page'}
/>
</div>
<DrawerFooter className="flex flex-row-reverse items-center justify-end px-0 pt-5">
@@ -233,7 +224,7 @@ export const CategoryItem: React.FC<{ item: StoredContent }> = ({ item }) => {
onReorder={setItems}
as="div"
initial={{ height: 0 }}
- animate={{ height: "auto" }}
+ animate={{ height: 'auto' }}
exit={{
height: 0,
transition: {},
@@ -281,8 +272,8 @@ export const CategoryPage: React.FC<{
>
<div className="relative h-4 min-w-4">
<img
- src={item.image ?? "/brain.png"}
- alt={item.title ?? "Untitiled website"}
+ src={item.image ?? '/brain.png'}
+ alt={item.title ?? 'Untitiled website'}
className="z-1 h-4 w-4 transition-[transform,opacity] delay-150 duration-150"
/>
<ArrowUpRight
@@ -293,7 +284,7 @@ export const CategoryPage: React.FC<{
</div>
<span className="w-full truncate text-nowrap">
- {item.title ?? "Untitled website"}
+ {item.title ?? 'Untitled website'}
</span>
</a>
<button
diff --git a/apps/web/src/components/Sidebar/MemoriesBar.tsx b/apps/web/src/components/Sidebar/MemoriesBar.tsx
index 9fcd3ff8..889a3ab7 100644
--- a/apps/web/src/components/Sidebar/MemoriesBar.tsx
+++ b/apps/web/src/components/Sidebar/MemoriesBar.tsx
@@ -76,7 +76,6 @@ const SpaceExitVariant: Variant = {
export function SpaceItem({
title,
- description,
content,
id,
onDelete,
diff --git a/apps/web/src/server/db/schema.ts b/apps/web/src/server/db/schema.ts
index d66965c4..a80eb7cf 100644
--- a/apps/web/src/server/db/schema.ts
+++ b/apps/web/src/server/db/schema.ts
@@ -87,7 +87,6 @@ export const storedContent = createTable(
title: text("title", { length: 255 }),
description: text("description", { length: 255 }),
url: text("url").notNull(),
- space: text("space", { length: 255 }).references(() => spaces.name).default('all'),
savedAt: int("savedAt", { mode: "timestamp" }).notNull(),
baseUrl: text("baseUrl", { length: 255 }),
image: text("image", { length: 255 }),
@@ -97,20 +96,31 @@ export const storedContent = createTable(
urlIdx: index("storedContent_url_idx").on(sc.url),
savedAtIdx: index("storedContent_savedAt_idx").on(sc.savedAt),
titleInx: index("storedContent_title_idx").on(sc.title),
- spaceIdx: index("storedContent_space_idx").on(sc.space),
userIdx: index("storedContent_user_idx").on(sc.user),
}),
);
-export const spaces = createTable(
- "spaces",
+export const contentToSpace = createTable(
+ "contentToSpace",
+ {
+ contentId: integer("contentId").notNull().references(() => storedContent.id),
+ spaceId: integer("spaceId").notNull().references(() => space.id),
+ },
+ (cts) => ({
+ compoundKey: primaryKey({ columns: [cts.contentId, cts.spaceId] }),
+ }),
+);
+
+export const space = createTable(
+ "space",
{
id: integer("id").notNull().primaryKey({ autoIncrement: true }),
name: text('name').notNull().default('all'),
- description: text("description", { length: 255 }),
+ user: text("user", { length: 255 }).references(() => users.id),
},
(space) => ({
nameIdx: index("spaces_name_idx").on(space.name),
+ userIdx: index("spaces_user_idx").on(space.user),
}),
);
diff --git a/apps/web/types/memory.tsx b/apps/web/types/memory.tsx
index a0194184..0674284d 100644
--- a/apps/web/types/memory.tsx
+++ b/apps/web/types/memory.tsx
@@ -1,21 +1,37 @@
-import { StoredContent } from '@/server/db/schema';
+import { db } from '@/server/db';
+import { contentToSpace, space, StoredContent } from '@/server/db/schema';
+import { eq, inArray, or } from 'drizzle-orm';
-export const transformContent = (content: StoredContent[]): CollectedSpaces[] => {
- const spaces = Array.from(new Set(content.map((c) => c.space)));
+export const transformContent = async (
+ content: StoredContent[],
+): Promise<CollectedSpaces[]> => {
+ const collectedSpaces = await db
+ .select({
+ id: space.id,
+ name: space.name,
+ contentId: contentToSpace.contentId,
+ })
+ .from(space)
+ .leftJoin(contentToSpace, eq(space.id, contentToSpace.spaceId))
+ .where(
+ inArray(
+ contentToSpace.contentId,
+ content.map((c: StoredContent) => c.id),
+ ),
+ )
+ .all();
- const spaceContent = spaces.map((space, i) => ({
- title: space!,
- id: i + 1,
- description: '',
- content: content.filter((c) => c.space === space),
+ const result = collectedSpaces.map((s) => ({
+ id: s.id,
+ title: s.name,
+ content: content.filter((c) => c.id === s.contentId),
}));
- return spaceContent;
+ return result;
};
export type CollectedSpaces = {
id: number;
title: string;
- description: string;
content: StoredContent[];
};