mirror of
https://github.com/supermemoryai/supermemory.git
synced 2026-09-07 08:26:15 +00:00
Fix biome lint/format errors: aria-hidden on SVGs, Infinity -> Number.POSITIVE_INFINITY, line length formatting
This commit is contained in:
parent
e7676763a9
commit
3eab287959
12 changed files with 348 additions and 114 deletions
|
|
@ -62,8 +62,6 @@ export default function Home() {
|
|||
const [documents, setDocuments] = useState<DocumentWithMemories[]>([])
|
||||
const [isLoading, setIsLoading] = 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 [stressTestCount, setStressTestCount] = useState(0)
|
||||
|
||||
|
|
@ -114,8 +112,6 @@ export default function Home() {
|
|||
setDocuments(data.documents)
|
||||
}
|
||||
|
||||
setCurrentPage(data.pagination.currentPage)
|
||||
setHasMore(data.pagination.currentPage < data.pagination.totalPages)
|
||||
setShowGraph(true)
|
||||
setMockData(null)
|
||||
setStressTestCount(0)
|
||||
|
|
@ -132,7 +128,6 @@ export default function Home() {
|
|||
e.preventDefault()
|
||||
if (apiKey) {
|
||||
setDocuments([])
|
||||
setCurrentPage(0)
|
||||
fetchDocuments(1)
|
||||
}
|
||||
}
|
||||
|
|
@ -172,9 +167,7 @@ export default function Home() {
|
|||
return toGraphDocuments(documents)
|
||||
}, [documents, mockData])
|
||||
|
||||
const displayCount = mockData
|
||||
? stressTestCount
|
||||
: documents.length
|
||||
const displayCount = mockData ? stressTestCount : documents.length
|
||||
|
||||
return (
|
||||
<div className="flex flex-col h-screen bg-zinc-950">
|
||||
|
|
@ -215,9 +208,7 @@ export default function Home() {
|
|||
<div className="flex items-center gap-6">
|
||||
<div className="flex items-center gap-2">
|
||||
<span className="text-zinc-400">Documents:</span>
|
||||
<span className="font-mono text-emerald-400">
|
||||
{displayCount}
|
||||
</span>
|
||||
<span className="font-mono text-emerald-400">{displayCount}</span>
|
||||
</div>
|
||||
{stressTestCount > 0 && (
|
||||
<span className="rounded bg-amber-900/50 px-2 py-0.5 text-xs text-amber-400">
|
||||
|
|
@ -257,6 +248,7 @@ export default function Home() {
|
|||
height="12"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
{isSlideshowActive ? (
|
||||
<rect x="6" y="6" width="12" height="12" />
|
||||
|
|
@ -281,6 +273,7 @@ export default function Home() {
|
|||
fill="none"
|
||||
viewBox="0 0 24 24"
|
||||
stroke="currentColor"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path
|
||||
strokeLinecap="round"
|
||||
|
|
|
|||
|
|
@ -2,7 +2,9 @@ import { describe, it, expect } from "vitest"
|
|||
import { VersionChainIndex } from "../canvas/version-chain"
|
||||
import type { GraphApiDocument, GraphApiMemory } from "../types"
|
||||
|
||||
function makeMem(overrides: Partial<GraphApiMemory> & { id: string }): GraphApiMemory {
|
||||
function makeMem(
|
||||
overrides: Partial<GraphApiMemory> & { id: string },
|
||||
): GraphApiMemory {
|
||||
return {
|
||||
memory: `Memory ${overrides.id}`,
|
||||
isStatic: false,
|
||||
|
|
@ -37,9 +39,7 @@ function makeDoc(id: string, memories: GraphApiMemory[]): GraphApiDocument {
|
|||
describe("VersionChainIndex", () => {
|
||||
it("getChain returns null for version 1 memories (no chain)", () => {
|
||||
const idx = new VersionChainIndex()
|
||||
const doc = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
])
|
||||
const doc = makeDoc("d1", [makeMem({ id: "m1", version: 1 })])
|
||||
idx.rebuild([doc])
|
||||
// version <= 1 returns null per implementation
|
||||
expect(idx.getChain("m1")).toBeNull()
|
||||
|
|
@ -49,8 +49,18 @@ describe("VersionChainIndex", () => {
|
|||
const idx = new VersionChainIndex()
|
||||
const doc = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
makeMem({ id: "m3", parentMemoryId: "m2", rootMemoryId: "m1", version: 3 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
makeMem({
|
||||
id: "m3",
|
||||
parentMemoryId: "m2",
|
||||
rootMemoryId: "m1",
|
||||
version: 3,
|
||||
}),
|
||||
])
|
||||
idx.rebuild([doc])
|
||||
|
||||
|
|
@ -65,8 +75,18 @@ describe("VersionChainIndex", () => {
|
|||
const idx = new VersionChainIndex()
|
||||
const doc = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
makeMem({ id: "m3", parentMemoryId: "m2", rootMemoryId: "m1", version: 3 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
makeMem({
|
||||
id: "m3",
|
||||
parentMemoryId: "m2",
|
||||
rootMemoryId: "m1",
|
||||
version: 3,
|
||||
}),
|
||||
])
|
||||
idx.rebuild([doc])
|
||||
|
||||
|
|
@ -82,7 +102,12 @@ describe("VersionChainIndex", () => {
|
|||
const idx = new VersionChainIndex()
|
||||
const doc = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
])
|
||||
idx.rebuild([doc])
|
||||
|
||||
|
|
@ -109,7 +134,12 @@ describe("VersionChainIndex", () => {
|
|||
const idx = new VersionChainIndex()
|
||||
const doc1 = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
])
|
||||
idx.rebuild([doc1])
|
||||
expect(idx.getChain("m2")).not.toBeNull()
|
||||
|
|
@ -123,10 +153,17 @@ describe("VersionChainIndex", () => {
|
|||
|
||||
it("rebuild skips if same array reference", () => {
|
||||
const idx = new VersionChainIndex()
|
||||
const docs = [makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
])]
|
||||
const docs = [
|
||||
makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
]),
|
||||
]
|
||||
idx.rebuild(docs)
|
||||
const chain1 = idx.getChain("m2")
|
||||
|
||||
|
|
@ -141,11 +178,21 @@ describe("VersionChainIndex", () => {
|
|||
const docs = [
|
||||
makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1 }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2 }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
}),
|
||||
]),
|
||||
makeDoc("d2", [
|
||||
makeMem({ id: "m3", version: 1 }),
|
||||
makeMem({ id: "m4", parentMemoryId: "m3", rootMemoryId: "m3", version: 2 }),
|
||||
makeMem({
|
||||
id: "m4",
|
||||
parentMemoryId: "m3",
|
||||
rootMemoryId: "m3",
|
||||
version: 2,
|
||||
}),
|
||||
]),
|
||||
]
|
||||
idx.rebuild(docs)
|
||||
|
|
@ -162,7 +209,13 @@ describe("VersionChainIndex", () => {
|
|||
const idx = new VersionChainIndex()
|
||||
const doc = makeDoc("d1", [
|
||||
makeMem({ id: "m1", version: 1, isForgotten: true, isLatest: false }),
|
||||
makeMem({ id: "m2", parentMemoryId: "m1", rootMemoryId: "m1", version: 2, isLatest: true }),
|
||||
makeMem({
|
||||
id: "m2",
|
||||
parentMemoryId: "m1",
|
||||
rootMemoryId: "m1",
|
||||
version: 2,
|
||||
isLatest: true,
|
||||
}),
|
||||
])
|
||||
idx.rebuild([doc])
|
||||
|
||||
|
|
|
|||
|
|
@ -185,7 +185,9 @@ describe("ViewportState", () => {
|
|||
|
||||
it("fitToNodes handles single node without throwing", () => {
|
||||
const vp = new ViewportState()
|
||||
expect(() => vp.fitToNodes([makeNode("a", 500, 500)], 800, 600)).not.toThrow()
|
||||
expect(() =>
|
||||
vp.fitToNodes([makeNode("a", 500, 500)], 800, 600),
|
||||
).not.toThrow()
|
||||
})
|
||||
|
||||
it("fitToNodes handles empty nodes array without throwing", () => {
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ function drawDocDocLines(
|
|||
const cy = Math.floor(d.y / CELL)
|
||||
let best1 = -1
|
||||
let best2 = -1
|
||||
let dist1 = Infinity
|
||||
let dist2 = Infinity
|
||||
let dist1 = Number.POSITIVE_INFINITY
|
||||
let dist2 = Number.POSITIVE_INFINITY
|
||||
|
||||
for (let dx = -1; dx <= 1; dx++) {
|
||||
for (let dy = -1; dy <= 1; dy++) {
|
||||
|
|
|
|||
|
|
@ -108,7 +108,10 @@ export const GraphCanvas = memo<ExtendedGraphCanvasProps>(function GraphCanvas({
|
|||
|
||||
// Track node ID changes for smart simulation re-init
|
||||
useEffect(() => {
|
||||
const idKey = nodes.map((n) => n.id).sort().join(",")
|
||||
const idKey = nodes
|
||||
.map((n) => n.id)
|
||||
.sort()
|
||||
.join(",")
|
||||
if (idKey !== prevIdsRef.current) {
|
||||
prevIdsRef.current = idKey
|
||||
// IDs changed - full re-init needed (handled by parent)
|
||||
|
|
@ -280,7 +283,11 @@ export const GraphCanvas = memo<ExtendedGraphCanvasProps>(function GraphCanvas({
|
|||
ctx.save()
|
||||
ctx.resetTransform()
|
||||
// Scale for DPR
|
||||
const d = Math.min(16384 / cur.width, 16384 / cur.height, dprRef.current)
|
||||
const d = Math.min(
|
||||
16384 / cur.width,
|
||||
16384 / cur.height,
|
||||
dprRef.current,
|
||||
)
|
||||
ctx.scale(d, d)
|
||||
ctx.fillStyle = "rgba(0,0,0,0.7)"
|
||||
ctx.fillRect(8, 8, 140, 52)
|
||||
|
|
|
|||
|
|
@ -76,6 +76,7 @@ function ChevronDownIcon({ color }: { color: string }) {
|
|||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
style={{ flexShrink: 0 }}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="m6 9 6 6 6-6" />
|
||||
</svg>
|
||||
|
|
@ -94,6 +95,7 @@ function ChevronRightIcon({ color }: { color: string }) {
|
|||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
style={{ flexShrink: 0 }}
|
||||
aria-hidden="true"
|
||||
>
|
||||
<path d="m9 18 6-6-6-6" />
|
||||
</svg>
|
||||
|
|
@ -160,7 +162,11 @@ function StatRow({
|
|||
|
||||
return (
|
||||
<div style={{ display: "flex", flexDirection: "column" }}>
|
||||
<button onClick={expandable ? onToggle : undefined} style={buttonStyle} type="button">
|
||||
<button
|
||||
onClick={expandable ? onToggle : undefined}
|
||||
style={buttonStyle}
|
||||
type="button"
|
||||
>
|
||||
<div style={leftStyle}>
|
||||
{icon}
|
||||
<span style={labelStyle}>{label}</span>
|
||||
|
|
@ -279,11 +285,20 @@ export const Legend = memo(function Legend({
|
|||
</button>
|
||||
|
||||
{isExpanded && (
|
||||
<div style={{ marginTop: 16, display: "flex", flexDirection: "column", gap: 16 }}>
|
||||
<div
|
||||
style={{
|
||||
marginTop: 16,
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 16,
|
||||
}}
|
||||
>
|
||||
{/* Statistics section */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
<span style={sectionLabelStyle}>Statistics</span>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: 6 }}
|
||||
>
|
||||
<StatRow
|
||||
count={memoryCount}
|
||||
icon={
|
||||
|
|
@ -354,16 +369,22 @@ export const Legend = memo(function Legend({
|
|||
</svg>
|
||||
}
|
||||
label="Connections"
|
||||
onToggle={() => setConnectionsExpanded(!connectionsExpanded)}
|
||||
onToggle={() =>
|
||||
setConnectionsExpanded(!connectionsExpanded)
|
||||
}
|
||||
colors={colors}
|
||||
>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
||||
<div
|
||||
style={{
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
gap: 6,
|
||||
}}
|
||||
>
|
||||
<div style={rowStyle}>
|
||||
<div style={rowLeftStyle}>
|
||||
<LineIcon color={colors.edgeDocMemory} />
|
||||
<span style={edgeLabelStyle}>
|
||||
Doc > Memory
|
||||
</span>
|
||||
<span style={edgeLabelStyle}>Doc > Memory</span>
|
||||
</div>
|
||||
</div>
|
||||
<div style={rowStyle}>
|
||||
|
|
@ -392,15 +413,15 @@ export const Legend = memo(function Legend({
|
|||
{/* Memory Status section */}
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 8 }}>
|
||||
<span style={sectionLabelStyle}>Memory Status</span>
|
||||
<div style={{ display: "flex", flexDirection: "column", gap: 6 }}>
|
||||
<div
|
||||
style={{ display: "flex", flexDirection: "column", gap: 6 }}
|
||||
>
|
||||
<div style={statusRowStyle}>
|
||||
<HexagonIcon
|
||||
fill={colors.memFill}
|
||||
stroke={colors.memBorderRecent}
|
||||
/>
|
||||
<span style={edgeLabelStyle}>
|
||||
Recent (< 24h)
|
||||
</span>
|
||||
<span style={edgeLabelStyle}>Recent (< 24h)</span>
|
||||
</div>
|
||||
<div style={statusRowStyle}>
|
||||
<HexagonIcon
|
||||
|
|
|
|||
|
|
@ -543,11 +543,9 @@ export function MemoryGraph({
|
|||
colors={colors}
|
||||
/>
|
||||
|
||||
{!isLoading &&
|
||||
!nodes.some((n) => n.type === "document") &&
|
||||
children && (
|
||||
<div style={emptyStateStyle}>{children}</div>
|
||||
)}
|
||||
{!isLoading && !nodes.some((n) => n.type === "document") && children && (
|
||||
<div style={emptyStateStyle}>{children}</div>
|
||||
)}
|
||||
|
||||
<div style={canvasContainerStyle} ref={containerRef}>
|
||||
{containerSize.width > 0 && containerSize.height > 0 && (
|
||||
|
|
@ -555,9 +553,7 @@ export function MemoryGraph({
|
|||
colors={colors}
|
||||
edges={edges}
|
||||
height={containerSize.height}
|
||||
highlightDocumentIds={
|
||||
highlightsVisible ? highlightDocumentIds : []
|
||||
}
|
||||
highlightDocumentIds={highlightsVisible ? highlightDocumentIds : []}
|
||||
nodes={nodes}
|
||||
onNodeClick={handleNodeClick}
|
||||
onNodeDragEnd={handleNodeDragEnd}
|
||||
|
|
|
|||
|
|
@ -418,7 +418,8 @@ export const NodeHoverPopover = memo<NodeHoverPopoverProps>(
|
|||
borderRadius: 12,
|
||||
overflow: "hidden",
|
||||
border: `1px solid ${colors.popoverBorder}`,
|
||||
boxShadow: "0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",
|
||||
boxShadow:
|
||||
"0 10px 15px -3px rgba(0,0,0,0.1), 0 4px 6px -4px rgba(0,0,0,0.1)",
|
||||
width: CARD_W,
|
||||
backgroundColor: colors.popoverBg,
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,34 +17,81 @@ function resolveColors(): GraphThemeColors {
|
|||
docStroke: readCssVar("--graph-doc-stroke", DEFAULT_COLORS.docStroke),
|
||||
docInnerFill: readCssVar("--graph-doc-inner", DEFAULT_COLORS.docInnerFill),
|
||||
memFill: readCssVar("--graph-mem-fill", DEFAULT_COLORS.memFill),
|
||||
memFillHover: readCssVar("--graph-mem-fill-hover", DEFAULT_COLORS.memFillHover),
|
||||
memStrokeDefault: readCssVar("--graph-mem-stroke", DEFAULT_COLORS.memStrokeDefault),
|
||||
memFillHover: readCssVar(
|
||||
"--graph-mem-fill-hover",
|
||||
DEFAULT_COLORS.memFillHover,
|
||||
),
|
||||
memStrokeDefault: readCssVar(
|
||||
"--graph-mem-stroke",
|
||||
DEFAULT_COLORS.memStrokeDefault,
|
||||
),
|
||||
accent: readCssVar("--graph-accent", DEFAULT_COLORS.accent),
|
||||
textPrimary: readCssVar("--graph-text-primary", DEFAULT_COLORS.textPrimary),
|
||||
textSecondary: readCssVar("--graph-text-secondary", DEFAULT_COLORS.textSecondary),
|
||||
textSecondary: readCssVar(
|
||||
"--graph-text-secondary",
|
||||
DEFAULT_COLORS.textSecondary,
|
||||
),
|
||||
textMuted: readCssVar("--graph-text-muted", DEFAULT_COLORS.textMuted),
|
||||
edgeDocMemory: readCssVar("--graph-edge-doc-mem", DEFAULT_COLORS.edgeDocMemory),
|
||||
edgeDocMemory: readCssVar(
|
||||
"--graph-edge-doc-mem",
|
||||
DEFAULT_COLORS.edgeDocMemory,
|
||||
),
|
||||
edgeVersion: readCssVar("--graph-edge-version", DEFAULT_COLORS.edgeVersion),
|
||||
edgeSimStrong: readCssVar("--graph-edge-sim-strong", DEFAULT_COLORS.edgeSimStrong),
|
||||
edgeSimMedium: readCssVar("--graph-edge-sim-medium", DEFAULT_COLORS.edgeSimMedium),
|
||||
edgeSimWeak: readCssVar("--graph-edge-sim-weak", DEFAULT_COLORS.edgeSimWeak),
|
||||
edgeSimStrong: readCssVar(
|
||||
"--graph-edge-sim-strong",
|
||||
DEFAULT_COLORS.edgeSimStrong,
|
||||
),
|
||||
edgeSimMedium: readCssVar(
|
||||
"--graph-edge-sim-medium",
|
||||
DEFAULT_COLORS.edgeSimMedium,
|
||||
),
|
||||
edgeSimWeak: readCssVar(
|
||||
"--graph-edge-sim-weak",
|
||||
DEFAULT_COLORS.edgeSimWeak,
|
||||
),
|
||||
edgeDocDoc: readCssVar("--graph-edge-doc-doc", DEFAULT_COLORS.edgeDocDoc),
|
||||
memBorderForgotten: readCssVar("--graph-mem-border-forgotten", DEFAULT_COLORS.memBorderForgotten),
|
||||
memBorderExpiring: readCssVar("--graph-mem-border-expiring", DEFAULT_COLORS.memBorderExpiring),
|
||||
memBorderRecent: readCssVar("--graph-mem-border-recent", DEFAULT_COLORS.memBorderRecent),
|
||||
memBorderForgotten: readCssVar(
|
||||
"--graph-mem-border-forgotten",
|
||||
DEFAULT_COLORS.memBorderForgotten,
|
||||
),
|
||||
memBorderExpiring: readCssVar(
|
||||
"--graph-mem-border-expiring",
|
||||
DEFAULT_COLORS.memBorderExpiring,
|
||||
),
|
||||
memBorderRecent: readCssVar(
|
||||
"--graph-mem-border-recent",
|
||||
DEFAULT_COLORS.memBorderRecent,
|
||||
),
|
||||
glowColor: readCssVar("--graph-glow", DEFAULT_COLORS.glowColor),
|
||||
iconColor: readCssVar("--graph-icon", DEFAULT_COLORS.iconColor),
|
||||
popoverBg: readCssVar("--graph-popover-bg", DEFAULT_COLORS.popoverBg),
|
||||
popoverBorder: readCssVar("--graph-popover-border", DEFAULT_COLORS.popoverBorder),
|
||||
popoverTextPrimary: readCssVar("--graph-popover-text-primary", DEFAULT_COLORS.popoverTextPrimary),
|
||||
popoverTextSecondary: readCssVar("--graph-popover-text-secondary", DEFAULT_COLORS.popoverTextSecondary),
|
||||
popoverTextMuted: readCssVar("--graph-popover-text-muted", DEFAULT_COLORS.popoverTextMuted),
|
||||
popoverBorder: readCssVar(
|
||||
"--graph-popover-border",
|
||||
DEFAULT_COLORS.popoverBorder,
|
||||
),
|
||||
popoverTextPrimary: readCssVar(
|
||||
"--graph-popover-text-primary",
|
||||
DEFAULT_COLORS.popoverTextPrimary,
|
||||
),
|
||||
popoverTextSecondary: readCssVar(
|
||||
"--graph-popover-text-secondary",
|
||||
DEFAULT_COLORS.popoverTextSecondary,
|
||||
),
|
||||
popoverTextMuted: readCssVar(
|
||||
"--graph-popover-text-muted",
|
||||
DEFAULT_COLORS.popoverTextMuted,
|
||||
),
|
||||
controlBg: readCssVar("--graph-control-bg", DEFAULT_COLORS.controlBg),
|
||||
controlBorder: readCssVar("--graph-control-border", DEFAULT_COLORS.controlBorder),
|
||||
controlBorder: readCssVar(
|
||||
"--graph-control-border",
|
||||
DEFAULT_COLORS.controlBorder,
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
export function useGraphTheme(overrides?: Partial<GraphThemeColors>): GraphThemeColors {
|
||||
export function useGraphTheme(
|
||||
overrides?: Partial<GraphThemeColors>,
|
||||
): GraphThemeColors {
|
||||
const [colors, setColors] = useState<GraphThemeColors>(() => resolveColors())
|
||||
|
||||
useEffect(() => {
|
||||
|
|
|
|||
|
|
@ -87,22 +87,112 @@ const MEMORY_TEMPLATES = [
|
|||
]
|
||||
|
||||
const TEMPLATE_FILLS: Record<string, string[]> = {
|
||||
preference: ["TypeScript", "dark mode", "keyboard shortcuts", "minimal UI", "detailed logs", "async patterns"],
|
||||
topic: ["authentication", "caching", "data sync", "graph rendering", "search indexing", "memory management"],
|
||||
approach: ["event sourcing", "CQRS", "microservices", "edge functions", "WebSocket streams", "batch processing"],
|
||||
requirement: ["10k concurrent users", "sub-100ms latency", "offline mode", "real-time updates", "GDPR compliance"],
|
||||
component: ["auth", "graph", "search", "storage", "notification", "analytics"],
|
||||
dependency: ["Redis", "PostgreSQL", "S3", "Cloudflare Workers", "D3-force", "WebGL"],
|
||||
purpose: ["caching", "persistence", "rendering", "indexing", "scheduling", "routing"],
|
||||
metric: ["p99 latency", "time to interactive", "memory usage", "CPU utilization", "bundle size"],
|
||||
preference: [
|
||||
"TypeScript",
|
||||
"dark mode",
|
||||
"keyboard shortcuts",
|
||||
"minimal UI",
|
||||
"detailed logs",
|
||||
"async patterns",
|
||||
],
|
||||
topic: [
|
||||
"authentication",
|
||||
"caching",
|
||||
"data sync",
|
||||
"graph rendering",
|
||||
"search indexing",
|
||||
"memory management",
|
||||
],
|
||||
approach: [
|
||||
"event sourcing",
|
||||
"CQRS",
|
||||
"microservices",
|
||||
"edge functions",
|
||||
"WebSocket streams",
|
||||
"batch processing",
|
||||
],
|
||||
requirement: [
|
||||
"10k concurrent users",
|
||||
"sub-100ms latency",
|
||||
"offline mode",
|
||||
"real-time updates",
|
||||
"GDPR compliance",
|
||||
],
|
||||
component: [
|
||||
"auth",
|
||||
"graph",
|
||||
"search",
|
||||
"storage",
|
||||
"notification",
|
||||
"analytics",
|
||||
],
|
||||
dependency: [
|
||||
"Redis",
|
||||
"PostgreSQL",
|
||||
"S3",
|
||||
"Cloudflare Workers",
|
||||
"D3-force",
|
||||
"WebGL",
|
||||
],
|
||||
purpose: [
|
||||
"caching",
|
||||
"persistence",
|
||||
"rendering",
|
||||
"indexing",
|
||||
"scheduling",
|
||||
"routing",
|
||||
],
|
||||
metric: [
|
||||
"p99 latency",
|
||||
"time to interactive",
|
||||
"memory usage",
|
||||
"CPU utilization",
|
||||
"bundle size",
|
||||
],
|
||||
threshold: ["200ms", "500ms", "50MB", "3 seconds", "100KB", "1GB"],
|
||||
action: ["run benchmarks", "update dependencies", "write migration scripts", "review PRs", "deploy to staging"],
|
||||
action: [
|
||||
"run benchmarks",
|
||||
"update dependencies",
|
||||
"write migration scripts",
|
||||
"review PRs",
|
||||
"deploy to staging",
|
||||
],
|
||||
deadline: ["end of sprint", "next release", "Q4", "Friday", "the demo"],
|
||||
observation: ["confusion", "delight", "frustration", "efficiency gains", "unexpected usage patterns"],
|
||||
feature: ["the graph view", "search filters", "memory chains", "document upload", "sharing"],
|
||||
condition: ["high load", "cold start", "large datasets", "slow networks", "concurrent edits"],
|
||||
issue: ["memory leaks", "race conditions", "stale data", "layout thrashing", "connection drops"],
|
||||
oldThing: ["REST API", "MongoDB", "class components", "Webpack", "manual testing"],
|
||||
observation: [
|
||||
"confusion",
|
||||
"delight",
|
||||
"frustration",
|
||||
"efficiency gains",
|
||||
"unexpected usage patterns",
|
||||
],
|
||||
feature: [
|
||||
"the graph view",
|
||||
"search filters",
|
||||
"memory chains",
|
||||
"document upload",
|
||||
"sharing",
|
||||
],
|
||||
condition: [
|
||||
"high load",
|
||||
"cold start",
|
||||
"large datasets",
|
||||
"slow networks",
|
||||
"concurrent edits",
|
||||
],
|
||||
issue: [
|
||||
"memory leaks",
|
||||
"race conditions",
|
||||
"stale data",
|
||||
"layout thrashing",
|
||||
"connection drops",
|
||||
],
|
||||
oldThing: [
|
||||
"REST API",
|
||||
"MongoDB",
|
||||
"class components",
|
||||
"Webpack",
|
||||
"manual testing",
|
||||
],
|
||||
newThing: ["GraphQL", "PostgreSQL", "hooks", "Vite", "automated CI"],
|
||||
}
|
||||
|
||||
|
|
@ -134,16 +224,22 @@ function generateTitle(random: () => number): string {
|
|||
|
||||
function generateSummary(random: () => number): string | null {
|
||||
if (random() < 0.15) return null
|
||||
const template = SUMMARY_TEMPLATES[Math.floor(random() * SUMMARY_TEMPLATES.length)]
|
||||
const template =
|
||||
SUMMARY_TEMPLATES[Math.floor(random() * SUMMARY_TEMPLATES.length)]
|
||||
return fillTemplate(template, random)
|
||||
}
|
||||
|
||||
function generateMemoryContent(random: () => number): string {
|
||||
const template = MEMORY_TEMPLATES[Math.floor(random() * MEMORY_TEMPLATES.length)]
|
||||
const template =
|
||||
MEMORY_TEMPLATES[Math.floor(random() * MEMORY_TEMPLATES.length)]
|
||||
return fillTemplate(template, random)
|
||||
}
|
||||
|
||||
function generateISODate(random: () => number, baseMs: number, rangeMs: number): string {
|
||||
function generateISODate(
|
||||
random: () => number,
|
||||
baseMs: number,
|
||||
rangeMs: number,
|
||||
): string {
|
||||
const ms = baseMs + Math.floor(random() * rangeMs)
|
||||
return new Date(ms).toISOString()
|
||||
}
|
||||
|
|
@ -165,7 +261,12 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
const baseTime = new Date("2024-01-01T00:00:00Z").getTime()
|
||||
const timeRange = 1000 * 60 * 60 * 24 * 540 // ~540 days
|
||||
|
||||
const spaceIds = ["space-default", "space-work", "space-personal", "space-research"]
|
||||
const spaceIds = [
|
||||
"space-default",
|
||||
"space-work",
|
||||
"space-personal",
|
||||
"space-research",
|
||||
]
|
||||
|
||||
const documents: GraphApiDocument[] = []
|
||||
|
||||
|
|
@ -198,7 +299,11 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
|
||||
for (let m = 0; m < memCount; m++) {
|
||||
const memId = `mem-${docId}-${String(m).padStart(3, "0")}`
|
||||
const memCreatedAt = generateISODate(random, new Date(docCreatedAt).getTime(), 1000 * 60 * 60 * 24 * 14)
|
||||
const memCreatedAt = generateISODate(
|
||||
random,
|
||||
new Date(docCreatedAt).getTime(),
|
||||
1000 * 60 * 60 * 24 * 14,
|
||||
)
|
||||
const memUpdatedAt = generateISODate(
|
||||
random,
|
||||
new Date(memCreatedAt).getTime(),
|
||||
|
|
@ -244,7 +349,8 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
forgetReason = random() < 0.5 ? "superseded" : "user-requested"
|
||||
} else if (random() < 0.1) {
|
||||
// Expiring memory
|
||||
const expiryMs = Date.now() + Math.floor(random() * 1000 * 60 * 60 * 24 * 30)
|
||||
const expiryMs =
|
||||
Date.now() + Math.floor(random() * 1000 * 60 * 60 * 24 * 30)
|
||||
forgetAfter = new Date(expiryMs).toISOString()
|
||||
}
|
||||
|
||||
|
|
@ -273,7 +379,8 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
id: docId,
|
||||
title: generateTitle(random),
|
||||
summary: generateSummary(random),
|
||||
documentType: DOCUMENT_TYPES[Math.floor(random() * DOCUMENT_TYPES.length)],
|
||||
documentType:
|
||||
DOCUMENT_TYPES[Math.floor(random() * DOCUMENT_TYPES.length)],
|
||||
createdAt: docCreatedAt,
|
||||
updatedAt: docUpdatedAt,
|
||||
x,
|
||||
|
|
@ -285,7 +392,10 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
// Generate similarity edges between random document pairs
|
||||
const edges: GraphApiEdge[] = []
|
||||
const totalPossiblePairs = (documentCount * (documentCount - 1)) / 2
|
||||
const targetEdgeCount = Math.max(0, Math.floor(totalPossiblePairs * similarityEdgeRatio))
|
||||
const targetEdgeCount = Math.max(
|
||||
0,
|
||||
Math.floor(totalPossiblePairs * similarityEdgeRatio),
|
||||
)
|
||||
|
||||
// Use a set to avoid duplicate pairs
|
||||
const edgeSet = new Set<string>()
|
||||
|
|
@ -319,7 +429,7 @@ export function generateMockGraphData(options: MockGraphOptions = {}): {
|
|||
while (edges.length < targetEdgeCount && attempts < maxAttempts) {
|
||||
attempts++
|
||||
const i = Math.floor(random() * documentCount)
|
||||
let j = Math.floor(random() * documentCount)
|
||||
const j = Math.floor(random() * documentCount)
|
||||
if (i === j) continue
|
||||
const sourceIdx = Math.min(i, j)
|
||||
const targetIdx = Math.max(i, j)
|
||||
|
|
|
|||
|
|
@ -234,4 +234,8 @@ export interface LoadingIndicatorProps {
|
|||
}
|
||||
|
||||
// Re-export api-types for backward compatibility
|
||||
export type { DocumentWithMemories, MemoryEntry, DocumentsResponse } from "./api-types"
|
||||
export type {
|
||||
DocumentWithMemories,
|
||||
MemoryEntry,
|
||||
DocumentsResponse,
|
||||
} from "./api-types"
|
||||
|
|
|
|||
|
|
@ -1,22 +1,22 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationDir": "./dist",
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
"compilerOptions": {
|
||||
"target": "ES2020",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "bundler",
|
||||
"jsx": "react-jsx",
|
||||
"strict": true,
|
||||
"esModuleInterop": true,
|
||||
"skipLibCheck": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"declaration": true,
|
||||
"declarationDir": "./dist",
|
||||
"emitDeclarationOnly": true,
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src",
|
||||
"paths": {
|
||||
"@/*": ["./src/*"]
|
||||
}
|
||||
},
|
||||
"include": ["src"],
|
||||
"exclude": ["node_modules", "dist"]
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue