aboutsummaryrefslogtreecommitdiff
path: root/apps/memory-graph-playground/src/app/page.tsx
diff options
context:
space:
mode:
authornexxeln <[email protected]>2025-12-02 18:37:24 +0000
committernexxeln <[email protected]>2025-12-02 18:37:24 +0000
commitdfb0c05ab33cb20537002eaeb896e6b2ab35af25 (patch)
tree49ecaa46903671d96f2f9ebc5af688ab2ea2c7bd /apps/memory-graph-playground/src/app/page.tsx
parentFix: Update discord links in README.md and CONTRIBUTING.md (#598) (diff)
downloadsupermemory-dfb0c05ab33cb20537002eaeb896e6b2ab35af25.tar.xz
supermemory-dfb0c05ab33cb20537002eaeb896e6b2ab35af25.zip
add spaces selector with search (#600)update-memory-graph
relevant files to review: \- memory-graph.tsx \- spaces-dropdown.tsx \- spaces-dropdown.css.ts
Diffstat (limited to 'apps/memory-graph-playground/src/app/page.tsx')
-rw-r--r--apps/memory-graph-playground/src/app/page.tsx393
1 files changed, 232 insertions, 161 deletions
diff --git a/apps/memory-graph-playground/src/app/page.tsx b/apps/memory-graph-playground/src/app/page.tsx
index bf202554..7192c4c2 100644
--- a/apps/memory-graph-playground/src/app/page.tsx
+++ b/apps/memory-graph-playground/src/app/page.tsx
@@ -1,169 +1,240 @@
"use client"
-import { useState, useCallback } from 'react'
-import { MemoryGraph, type DocumentWithMemories } from '@supermemory/memory-graph'
+import { useState, useCallback } from "react"
+import {
+ MemoryGraph,
+ type DocumentWithMemories,
+} from "@supermemory/memory-graph"
interface DocumentsResponse {
- documents: DocumentWithMemories[]
- pagination: {
- currentPage: number
- limit: number
- totalItems: number
- totalPages: number
- }
+ documents: DocumentWithMemories[]
+ pagination: {
+ currentPage: number
+ limit: number
+ totalItems: number
+ totalPages: number
+ }
}
export default function Home() {
- const [apiKey, setApiKey] = useState('')
- const [documents, setDocuments] = useState<DocumentWithMemories[]>([])
- const [isLoading, setIsLoading] = useState(false)
- const [isLoadingMore, setIsLoadingMore] = useState(false)
- const [error, setError] = useState<Error | null>(null)
- const [hasMore, setHasMore] = useState(false)
- const [currentPage, setCurrentPage] = useState(0)
- const [showGraph, setShowGraph] = useState(false)
-
- const PAGE_SIZE = 500
-
- const fetchDocuments = useCallback(async (page: number, append = false) => {
- if (!apiKey) return
-
- if (page === 1) {
- setIsLoading(true)
- } else {
- setIsLoadingMore(true)
- }
- setError(null)
-
- try {
- const response = await fetch('/api/graph', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- },
- body: JSON.stringify({
- apiKey,
- page,
- limit: PAGE_SIZE,
- sort: 'createdAt',
- order: 'desc',
- }),
- })
-
- if (!response.ok) {
- const errorData = await response.json()
- throw new Error(errorData.error || 'Failed to fetch documents')
- }
-
- const data: DocumentsResponse = await response.json()
-
- if (append) {
- setDocuments(prev => [...prev, ...data.documents])
- } else {
- setDocuments(data.documents)
- }
-
- setCurrentPage(data.pagination.currentPage)
- setHasMore(data.pagination.currentPage < data.pagination.totalPages)
- setShowGraph(true)
- } catch (err) {
- setError(err instanceof Error ? err : new Error('Unknown error'))
- } finally {
- setIsLoading(false)
- setIsLoadingMore(false)
- }
- }, [apiKey])
-
- const loadMoreDocuments = useCallback(async () => {
- if (hasMore && !isLoadingMore) {
- await fetchDocuments(currentPage + 1, true)
- }
- }, [hasMore, isLoadingMore, currentPage, fetchDocuments])
-
- const handleSubmit = (e: React.FormEvent) => {
- e.preventDefault()
- if (apiKey) {
- setDocuments([])
- setCurrentPage(0)
- fetchDocuments(1)
- }
- }
-
- return (
- <div className="flex flex-col h-screen bg-zinc-950">
- {/* Header */}
- <header className="shrink-0 border-b border-zinc-800 bg-zinc-900 px-6 py-4">
- <div className="flex items-center justify-between">
- <div>
- <h1 className="text-xl font-semibold text-white">Memory Graph Playground</h1>
- <p className="text-sm text-zinc-400">Test the @supermemory/memory-graph package</p>
- </div>
-
- <form onSubmit={handleSubmit} className="flex items-center gap-3">
- <input
- type="password"
- placeholder="Enter your Supermemory API key"
- value={apiKey}
- onChange={(e) => setApiKey(e.target.value)}
- className="w-80 rounded-lg border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-white placeholder-zinc-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
- />
- <button
- type="submit"
- disabled={!apiKey || isLoading}
- className="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
- >
- {isLoading ? 'Loading...' : 'Load Graph'}
- </button>
- </form>
- </div>
- </header>
-
- {/* Main content */}
- <main className="flex-1 overflow-hidden">
- {!showGraph ? (
- <div className="flex h-full items-center justify-center">
- <div className="max-w-md text-center">
- <div className="mb-6 text-6xl">
- <svg className="mx-auto h-16 w-16 text-zinc-600" fill="none" viewBox="0 0 24 24" stroke="currentColor">
- <path strokeLinecap="round" strokeLinejoin="round" strokeWidth={1.5} d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1" />
- </svg>
- </div>
- <h2 className="mb-2 text-xl font-semibold text-white">Get Started</h2>
- <p className="mb-6 text-zinc-400">
- Enter your Supermemory API key above to visualize your memory graph.
- </p>
- <div className="text-left text-sm text-zinc-500">
- <p className="mb-2 font-medium text-zinc-400">Features to test:</p>
- <ul className="list-inside list-disc space-y-1">
- <li>Pan and zoom the graph</li>
- <li>Click on nodes to see details</li>
- <li>Drag nodes around</li>
- <li>Use the space selector to filter</li>
- <li>Pagination loads more documents</li>
- </ul>
- </div>
- </div>
- </div>
- ) : (
- <div className="h-full w-full">
- <MemoryGraph
- documents={documents}
- isLoading={isLoading}
- isLoadingMore={isLoadingMore}
- error={error}
- hasMore={hasMore}
- loadMoreDocuments={loadMoreDocuments}
- totalLoaded={documents.length}
- variant="console"
- showSpacesSelector={true}
- >
- <div className="flex h-full items-center justify-center">
- <p className="text-zinc-400">No memories found. Add some content to see your graph.</p>
- </div>
- </MemoryGraph>
- </div>
- )}
- </main>
- </div>
- )
+ const [apiKey, setApiKey] = useState("")
+ const [documents, setDocuments] = useState<DocumentWithMemories[]>([])
+ const [isLoading, setIsLoading] = useState(false)
+ const [isLoadingMore, setIsLoadingMore] = useState(false)
+ const [error, setError] = useState<Error | null>(null)
+ const [hasMore, setHasMore] = useState(false)
+ const [currentPage, setCurrentPage] = useState(0)
+ const [showGraph, setShowGraph] = useState(false)
+
+ // State for controlled space selection
+ const [selectedSpace, setSelectedSpace] = useState<string>("all")
+
+ const PAGE_SIZE = 500
+
+ const fetchDocuments = useCallback(
+ async (page: number, append = false) => {
+ if (!apiKey) return
+
+ if (page === 1) {
+ setIsLoading(true)
+ } else {
+ setIsLoadingMore(true)
+ }
+ setError(null)
+
+ try {
+ const response = await fetch("/api/graph", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ },
+ body: JSON.stringify({
+ apiKey,
+ page,
+ limit: PAGE_SIZE,
+ sort: "createdAt",
+ order: "desc",
+ }),
+ })
+
+ if (!response.ok) {
+ const errorData = await response.json()
+ throw new Error(errorData.error || "Failed to fetch documents")
+ }
+
+ const data: DocumentsResponse = await response.json()
+
+ if (append) {
+ setDocuments((prev) => [...prev, ...data.documents])
+ } else {
+ setDocuments(data.documents)
+ }
+
+ setCurrentPage(data.pagination.currentPage)
+ setHasMore(data.pagination.currentPage < data.pagination.totalPages)
+ setShowGraph(true)
+ } catch (err) {
+ setError(err instanceof Error ? err : new Error("Unknown error"))
+ } finally {
+ setIsLoading(false)
+ setIsLoadingMore(false)
+ }
+ },
+ [apiKey],
+ )
+
+ const loadMoreDocuments = useCallback(async () => {
+ if (hasMore && !isLoadingMore) {
+ await fetchDocuments(currentPage + 1, true)
+ }
+ }, [hasMore, isLoadingMore, currentPage, fetchDocuments])
+
+ const handleSubmit = (e: React.FormEvent) => {
+ e.preventDefault()
+ if (apiKey) {
+ setDocuments([])
+ setCurrentPage(0)
+ setSelectedSpace("all")
+ fetchDocuments(1)
+ }
+ }
+
+ // Handle space change
+ const handleSpaceChange = useCallback((spaceId: string) => {
+ setSelectedSpace(spaceId)
+ }, [])
+
+ // Reset to defaults
+ const handleReset = () => {
+ setSelectedSpace("all")
+ }
+
+ return (
+ <div className="flex flex-col h-screen bg-zinc-950">
+ {/* Header */}
+ <header className="shrink-0 border-b border-zinc-800 bg-zinc-900 px-6 py-4">
+ <div className="flex items-center justify-between">
+ <div>
+ <h1 className="text-xl font-semibold text-white">
+ Memory Graph Playground
+ </h1>
+ <p className="text-sm text-zinc-400">
+ Test the @supermemory/memory-graph package
+ </p>
+ </div>
+
+ <form onSubmit={handleSubmit} className="flex items-center gap-3">
+ <input
+ type="password"
+ placeholder="Enter your Supermemory API key"
+ value={apiKey}
+ onChange={(e) => setApiKey(e.target.value)}
+ className="w-80 rounded-lg border border-zinc-700 bg-zinc-800 px-4 py-2 text-sm text-white placeholder-zinc-500 focus:border-blue-500 focus:outline-none focus:ring-1 focus:ring-blue-500"
+ />
+ <button
+ type="submit"
+ disabled={!apiKey || isLoading}
+ className="rounded-lg bg-blue-600 px-4 py-2 text-sm font-medium text-white transition-colors hover:bg-blue-700 disabled:cursor-not-allowed disabled:opacity-50"
+ >
+ {isLoading ? "Loading..." : "Load Graph"}
+ </button>
+ </form>
+ </div>
+ </header>
+
+ {/* State Display Panel - For Testing */}
+ {showGraph && (
+ <div className="shrink-0 border-b border-zinc-800 bg-zinc-900/50 px-6 py-3">
+ <div className="flex items-center justify-between text-sm">
+ <div className="flex items-center gap-6">
+ <div className="flex items-center gap-2">
+ <span className="text-zinc-400">Selected Space:</span>
+ <span className="font-mono text-blue-400">{selectedSpace}</span>
+ </div>
+ <div className="flex items-center gap-2">
+ <span className="text-zinc-400">Documents:</span>
+ <span className="font-mono text-emerald-400">
+ {documents.length}
+ </span>
+ </div>
+ </div>
+ <button
+ onClick={handleReset}
+ className="rounded-lg border border-zinc-700 px-3 py-1 text-xs font-medium text-zinc-300 transition-colors hover:bg-zinc-800"
+ >
+ Reset Filters
+ </button>
+ </div>
+ </div>
+ )}
+
+ {/* Main content */}
+ <main className="flex-1 overflow-hidden">
+ {!showGraph ? (
+ <div className="flex h-full items-center justify-center">
+ <div className="max-w-md text-center">
+ <div className="mb-6 text-6xl">
+ <svg
+ className="mx-auto h-16 w-16 text-zinc-600"
+ fill="none"
+ viewBox="0 0 24 24"
+ stroke="currentColor"
+ >
+ <path
+ strokeLinecap="round"
+ strokeLinejoin="round"
+ strokeWidth={1.5}
+ d="M13.828 10.172a4 4 0 00-5.656 0l-4 4a4 4 0 105.656 5.656l1.102-1.101m-.758-4.899a4 4 0 005.656 0l4-4a4 4 0 00-5.656-5.656l-1.1 1.1"
+ />
+ </svg>
+ </div>
+ <h2 className="mb-2 text-xl font-semibold text-white">
+ Get Started
+ </h2>
+ <p className="mb-6 text-zinc-400">
+ Enter your Supermemory API key above to visualize your memory
+ graph.
+ </p>
+ <div className="text-left text-sm text-zinc-500">
+ <p className="mb-2 font-medium text-zinc-400">
+ Features to test:
+ </p>
+ <ul className="list-inside list-disc space-y-1">
+ <li>✨ Search and filter by spaces</li>
+ <li>✨ Arrow key navigation in spaces dropdown</li>
+ <li>Pan and zoom the graph</li>
+ <li>Click on nodes to see details</li>
+ <li>Drag nodes around</li>
+ <li>Filter by space</li>
+ <li>Pagination loads more documents</li>
+ </ul>
+ </div>
+ </div>
+ </div>
+ ) : (
+ <div className="h-full w-full">
+ <MemoryGraph
+ documents={documents}
+ isLoading={isLoading}
+ isLoadingMore={isLoadingMore}
+ error={error}
+ hasMore={hasMore}
+ loadMoreDocuments={loadMoreDocuments}
+ totalLoaded={documents.length}
+ variant="consumer"
+ // Controlled space selection
+ selectedSpace={selectedSpace}
+ onSpaceChange={handleSpaceChange}
+ >
+ <div className="flex h-full items-center justify-center">
+ <p className="text-zinc-400">
+ No memories found. Add some content to see your graph.
+ </p>
+ </div>
+ </MemoryGraph>
+ </div>
+ )}
+ </main>
+ </div>
+ )
}