Fix biome lint/format errors: aria-hidden on SVGs, Infinity -> Number.POSITIVE_INFINITY, line length formatting

This commit is contained in:
Vorflux AI 2026-03-27 00:12:50 +00:00
parent e7676763a9
commit 3eab287959
12 changed files with 348 additions and 114 deletions

View file

@ -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"

View file

@ -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])

View file

@ -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", () => {

View file

@ -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++) {

View file

@ -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)

View file

@ -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 &gt; Memory
</span>
<span style={edgeLabelStyle}>Doc &gt; 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 (&lt; 24h)
</span>
<span style={edgeLabelStyle}>Recent (&lt; 24h)</span>
</div>
<div style={statusRowStyle}>
<HexagonIcon

View file

@ -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}

View file

@ -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,
}

View file

@ -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(() => {

View file

@ -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)

View file

@ -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"

View file

@ -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"]
}