@flexkit/studio 0.2.19 → 0.2.20
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{chat-page-LAK4TFN4.js → chat-page-4G4XQ26P.js} +3 -3
- package/dist/{chat-page-LAK4TFN4.js.map → chat-page-4G4XQ26P.js.map} +1 -1
- package/dist/{chunk-4IEOAKKK.js → chunk-2P2QV3K6.js} +2 -2
- package/dist/{chunk-4IEOAKKK.js.map → chunk-2P2QV3K6.js.map} +1 -1
- package/dist/{chunk-OOYCTZ3C.js → chunk-445XKMAG.js} +3 -3
- package/dist/{chunk-OOYCTZ3C.js.map → chunk-445XKMAG.js.map} +1 -1
- package/dist/{chunk-H2RWSC56.js → chunk-B7QMGBK5.js} +3 -3
- package/dist/{chunk-H2RWSC56.js.map → chunk-B7QMGBK5.js.map} +1 -1
- package/dist/{chunk-ZKA2HKNI.js → chunk-BXN72PW2.js} +2 -2
- package/dist/{chunk-ZKA2HKNI.js.map → chunk-BXN72PW2.js.map} +1 -1
- package/dist/{chunk-HCJAM5LG.js → chunk-F2DT6NRK.js} +2 -2
- package/dist/{chunk-HCJAM5LG.js.map → chunk-F2DT6NRK.js.map} +1 -1
- package/dist/{chunk-DFLAX7EE.js → chunk-HLHLBMLJ.js} +2 -2
- package/dist/{chunk-DFLAX7EE.js.map → chunk-HLHLBMLJ.js.map} +1 -1
- package/dist/{chunk-V6RB45UU.js → chunk-JWBER5NX.js} +2 -2
- package/dist/{chunk-V6RB45UU.js.map → chunk-JWBER5NX.js.map} +1 -1
- package/dist/{chunk-VMWUMFUL.js → chunk-LK67JOQA.js} +3 -3
- package/dist/{chunk-VMWUMFUL.js.map → chunk-LK67JOQA.js.map} +1 -1
- package/dist/{chunk-6RRB47OZ.js → chunk-MKK65RQB.js} +3 -3
- package/dist/{chunk-6RRB47OZ.js.map → chunk-MKK65RQB.js.map} +1 -1
- package/dist/{chunk-XNHSHVG2.js → chunk-NYSQU73M.js} +3 -3
- package/dist/{chunk-XNHSHVG2.js.map → chunk-NYSQU73M.js.map} +1 -1
- package/dist/{chunk-QWQHXMXW.js → chunk-RY6PECIT.js} +2 -2
- package/dist/{chunk-QWQHXMXW.js.map → chunk-RY6PECIT.js.map} +1 -1
- package/dist/{entry-3JSFO4OU.js → entry-XVLXKEQV.js} +2 -2
- package/dist/{entry-3JSFO4OU.js.map → entry-XVLXKEQV.js.map} +1 -1
- package/dist/index.css +3 -0
- package/dist/index.js +2 -2
- package/dist/{list-SY3L2ACH.js → list-4OJMI4CB.js} +3 -3
- package/dist/{list-SY3L2ACH.js.map → list-4OJMI4CB.js.map} +1 -1
- package/dist/{list-Z2C74QDN.js → list-RABV2F3H.js} +2 -2
- package/dist/{list-Z2C74QDN.js.map → list-RABV2F3H.js.map} +1 -1
- package/dist/{pages-INCA54HE.js → pages-7LWBCW2X.js} +3 -3
- package/dist/{pages-INCA54HE.js.map → pages-7LWBCW2X.js.map} +1 -1
- package/dist/{plugin-pages-WO3MCJKC.js → plugin-pages-PQWTH7P5.js} +2 -2
- package/dist/{plugin-pages-WO3MCJKC.js.map → plugin-pages-PQWTH7P5.js.map} +1 -1
- package/dist/{record-links-CTB4SC4J.js → record-links-BFHPBOAL.js} +2 -2
- package/dist/{record-links-CTB4SC4J.js.map → record-links-BFHPBOAL.js.map} +1 -1
- package/dist/{root-XHXX3SZG.js → root-BS6QCYLO.js} +3 -3
- package/dist/{root-XHXX3SZG.js.map → root-BS6QCYLO.js.map} +1 -1
- package/dist/{root-6MSWGFZX.js → root-COI626G2.js} +2 -2
- package/dist/{root-6MSWGFZX.js.map → root-COI626G2.js.map} +1 -1
- package/dist/{root-DOOWSYWY.js → root-FTT4XDCE.js} +3 -3
- package/dist/{root-DOOWSYWY.js.map → root-FTT4XDCE.js.map} +1 -1
- package/dist/{root-OGX4DUTM.js → root-PDSTTPHO.js} +2 -2
- package/dist/{root-OGX4DUTM.js.map → root-PDSTTPHO.js.map} +1 -1
- package/dist/{root-JA2LFGNX.js → root-RXMRNU4M.js} +2 -2
- package/dist/{root-JA2LFGNX.js.map → root-RXMRNU4M.js.map} +1 -1
- package/dist/root-TZYOIXVG.js +2 -0
- package/dist/root-TZYOIXVG.js.map +1 -0
- package/dist/{search-Z4M4R4NJ.js → search-VPS2UHPQ.js} +2 -2
- package/dist/{search-Z4M4R4NJ.js.map → search-VPS2UHPQ.js.map} +1 -1
- package/dist/{skills-pages-TP2XQPCQ.js → skills-pages-G6JK7KKQ.js} +2 -2
- package/dist/{skills-pages-TP2XQPCQ.js.map → skills-pages-G6JK7KKQ.js.map} +1 -1
- package/dist/{source-5J56KIFA.js → source-MNHZQD4T.js} +2 -2
- package/dist/{source-5J56KIFA.js.map → source-MNHZQD4T.js.map} +1 -1
- package/package.json +3 -3
- package/dist/root-B4D3C37Q.js +0 -2
- package/dist/root-B4D3C37Q.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/knowledge/source.tsx"],"names":["DETAIL_POLL_INTERVAL_MS","SourcePageHeader","actions","title","jsxs","Fragment","Tooltip","jsx","TooltipTrigger","SidebarTrigger","TooltipContent","Separator","Button","Link","ArrowLeft","SourceDetailSkeleton","Skeleton","SectionTitle","children","PassageList","projectId","source","version","passageCount","versionId","getPassagesKey","pageIndex","KNOWLEDGE_PASSAGES_PAGE_SIZE","from","knowledgePaths","pages","error","isLoading","setSize","size","useSWRInfinite","fetcher","passages","page","loaded","useEffect","passage","where","formatKnowledgeLocator","LoaderCircle","SourceSettings","api","onSaved","canMutate","useCanMutate","auth","useAuth","spacesData","useSWR","userSpaceCodes","projectSpaces","selectableSpaces","space","foreignSpaces","code","setTitle","useState","isSaving","setIsSaving","titleChanged","save","patch","result","invalidateKnowledgeLists","toast","describeApiError","disabled","spacesEmptyMessage","Alert","AlertDescription","Label","Input","KNOWLEDGE_MAX_TITLE_LENGTH","event","Switch","checked","Checkbox","toggleSpaceCode","Source","useProjectKnowledge","sourceId","useParams","navigate","useNavigate","isViewing","useIsViewing","isBusy","setIsBusy","isReindexing","setIsReindexing","data","mutate","isKnowledgeSourceBusy","PageMessage","job","status","summarizeKnowledgeStatus","isWorking","reindex","reindexError","facts","getKnowledgeKindLabel","ExternalLinkIcon","formatFileSize","formatDistance","PermissionTooltip","RefreshCwIcon","SourceActionsMenu","SourceIcon","StatusBadge","fact","warning","formatKnowledgeWarning","saved","LinkedRecordsSection","BookOpenIcon"],"mappings":"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","file":"source-5J56KIFA.js","sourcesContent":["import type { JSX } from 'react';\nimport { useEffect, useState } from 'react';\nimport { formatDistance } from 'date-fns';\nimport { ArrowLeft, BookOpenIcon, ExternalLinkIcon, LoaderCircle, RefreshCwIcon } from 'lucide-react';\nimport { Link, useNavigate, useParams } from 'react-router-dom';\nimport useSWR from 'swr';\nimport useSWRInfinite from 'swr/infinite';\nimport { useAuth } from '../../auth/auth-context';\nimport { useIsViewing } from '../../core/apps/app-active';\nimport { useCanMutate } from '../../core/permissions';\nimport {\n Alert,\n AlertDescription,\n Button,\n Checkbox,\n Input,\n Label,\n PermissionTooltip,\n Separator,\n SidebarTrigger,\n Skeleton,\n Switch,\n toast,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../../ui';\nimport { fetcher, knowledgePaths, type KnowledgeApi, type ProjectSpace } from './api';\nimport {\n formatFileSize,\n formatKnowledgeLocator,\n formatKnowledgeWarning,\n getKnowledgeKindLabel,\n isKnowledgeSourceBusy,\n KNOWLEDGE_MAX_TITLE_LENGTH,\n KNOWLEDGE_PASSAGES_PAGE_SIZE,\n summarizeKnowledgeStatus,\n toggleSpaceCode,\n type KnowledgePassage,\n type KnowledgePassagesPage,\n type KnowledgeSource,\n type KnowledgeSourceDetail,\n} from './knowledge';\nimport { LinkedRecordsSection } from './record-links';\nimport {\n describeApiError,\n invalidateKnowledgeLists,\n PageMessage,\n SourceActionsMenu,\n SourceIcon,\n StatusBadge,\n useProjectKnowledge,\n} from './shared';\n\nconst DETAIL_POLL_INTERVAL_MS = 2_000;\n\nfunction SourcePageHeader({ actions, title }: { actions?: JSX.Element; title: string }): JSX.Element {\n return (\n <>\n <div className=\"fk:flex fk:shrink-0 fk:items-center fk:gap-2 fk:pr-4\">\n <Tooltip>\n <TooltipTrigger asChild>\n <SidebarTrigger className=\"fk:-ml-1 fk:h-4 fk:w-4\" />\n </TooltipTrigger>\n <TooltipContent>Toggle Sidebar</TooltipContent>\n </Tooltip>\n <Separator orientation=\"vertical\" className=\"fk:h-4\" />\n <h1 className=\"fk:min-w-0 fk:flex-1 fk:truncate fk:text-lg fk:font-semibold fk:leading-none fk:tracking-tight\">\n {title}\n </h1>\n {actions}\n </div>\n <Button asChild className=\"fk:w-fit fk:shrink-0\" size=\"sm\" variant=\"ghost\">\n <Link relative=\"path\" to=\"..\">\n <ArrowLeft className=\"fk:mr-2 fk:size-4\" />\n All documents\n </Link>\n </Button>\n </>\n );\n}\n\nfunction SourceDetailSkeleton(): JSX.Element {\n return (\n <div aria-busy=\"true\" className=\"fk:flex fk:flex-col fk:gap-6 fk:py-6 fk:pl-4 fk:pr-6\">\n <span className=\"fk:sr-only\">Loading document</span>\n <Skeleton className=\"fk:h-6 fk:w-64\" />\n <Skeleton className=\"fk:h-4 fk:w-96\" />\n <Skeleton className=\"fk:h-32 fk:w-full\" />\n </div>\n );\n}\n\nfunction SectionTitle({ children }: { children: string }): JSX.Element {\n return <h3 className=\"fk:text-sm fk:font-semibold fk:tracking-tight\">{children}</h3>;\n}\n\nfunction PassageList({ projectId, source }: { projectId: string; source: KnowledgeSource }): JSX.Element {\n const version = source.currentVersion?.status === 'published' ? source.currentVersion : null;\n const passageCount = version?.passageCount ?? 0;\n const versionId = version?.id ?? null;\n const getPassagesKey = (pageIndex: number): string | null => {\n if (!versionId || pageIndex * KNOWLEDGE_PASSAGES_PAGE_SIZE >= passageCount) {\n return null;\n }\n\n const from = pageIndex * KNOWLEDGE_PASSAGES_PAGE_SIZE;\n const path = knowledgePaths(projectId).passages(source.id, {\n from,\n to: Math.min(from + KNOWLEDGE_PASSAGES_PAGE_SIZE - 1, passageCount - 1),\n });\n\n // The version is part of the key, so a re-index swaps the pages instead\n // of serving the retired ones; the server ignores the extra parameter.\n return `${path}&version=${encodeURIComponent(versionId)}`;\n };\n const {\n data: pages,\n error,\n isLoading,\n setSize,\n size,\n } = useSWRInfinite<KnowledgePassagesPage>(getPassagesKey, fetcher, {\n revalidateFirstPage: false,\n });\n const passages: KnowledgePassage[] = pages?.flatMap((page) => page.passages) ?? [];\n const loaded = passages.length;\n\n // A new version starts from its first page again.\n useEffect(() => {\n void setSize(1);\n }, [setSize, versionId]);\n\n if (passageCount === 0) {\n return <p className=\"fk:text-sm fk:text-muted-foreground\">Passages appear here once the document is indexed.</p>;\n }\n\n if (error) {\n return <p className=\"fk:text-sm fk:text-destructive\">The passages could not be loaded.</p>;\n }\n\n return (\n <div className=\"fk:flex fk:flex-col fk:gap-3\">\n {passages.map((passage) => {\n const where = formatKnowledgeLocator(passage.locator);\n\n return (\n <article\n className=\"fk:rounded-lg fk:border fk:bg-background fk:px-4 fk:py-3 fk:corner-squircle\"\n key={passage.id}\n >\n <header className=\"fk:mb-1.5 fk:flex fk:items-center fk:gap-2 fk:text-xs fk:text-muted-foreground\">\n <span className=\"fk:font-medium\">#{String(passage.order + 1)}</span>\n {where ? <span className=\"fk:truncate\">{where}</span> : null}\n </header>\n <p className=\"fk:whitespace-pre-wrap fk:text-sm fk:leading-relaxed\">{passage.text}</p>\n </article>\n );\n })}\n {isLoading ? (\n <div className=\"fk:flex fk:items-center fk:gap-2 fk:py-2 fk:text-sm fk:text-muted-foreground\">\n <LoaderCircle className=\"fk:size-4 fk:animate-spin\" />\n Loading passages…\n </div>\n ) : null}\n {loaded < passageCount && !isLoading ? (\n <Button className=\"fk:w-fit\" size=\"sm\" variant=\"outline\" onClick={() => void setSize(size + 1)}>\n Show more ({String(loaded)} of {String(passageCount)})\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction SourceSettings({\n api,\n onSaved,\n projectId,\n source,\n}: {\n api: KnowledgeApi;\n onSaved: (_source: KnowledgeSource) => void;\n projectId: string;\n source: KnowledgeSource;\n}): JSX.Element {\n const canMutate = useCanMutate();\n const [, auth] = useAuth();\n const { data: spacesData } = useSWR<{ spaces: ProjectSpace[] }>(knowledgePaths(projectId).spaces, fetcher);\n const userSpaceCodes = auth.user?.spaces ?? [];\n // Only the caller's own spaces are offered: changing a source needs every\n // space it is shared with, and the server refuses codes the caller lacks.\n const projectSpaces = spacesData?.spaces ?? [];\n const selectableSpaces = projectSpaces.filter((space) => userSpaceCodes.includes(space.code));\n const foreignSpaces = source.spaces.filter((code) => !userSpaceCodes.includes(code));\n const [title, setTitle] = useState(source.title);\n const [isSaving, setIsSaving] = useState(false);\n const titleChanged = title.trim() !== source.title && title.trim().length > 0;\n\n useEffect(() => {\n setTitle(source.title);\n }, [source.title]);\n\n async function save(patch: { agentVisible?: boolean; spaces?: string[]; title?: string }): Promise<void> {\n if (!canMutate) {\n return;\n }\n\n setIsSaving(true);\n\n try {\n const result = await api.updateSource(source.id, patch);\n\n onSaved(result.source);\n void invalidateKnowledgeLists();\n } catch (error) {\n toast.error(describeApiError(error, 'The document could not be updated.'));\n } finally {\n setIsSaving(false);\n }\n }\n\n const disabled = !canMutate || isSaving || foreignSpaces.length > 0;\n let spacesEmptyMessage = 'This project has no spaces yet, so every member can read it.';\n\n if (projectSpaces.length > 0) {\n spacesEmptyMessage = 'You are not a member of any space in this project.';\n }\n\n return (\n <div className=\"fk:flex fk:flex-col fk:gap-5\">\n {foreignSpaces.length > 0 ? (\n <Alert>\n <AlertDescription>\n This document is shared with spaces you are not a member of ({foreignSpaces.join(', ')}), so only an owner\n or a member of all of them can change it.\n </AlertDescription>\n </Alert>\n ) : null}\n <div className=\"fk:flex fk:flex-col fk:gap-1.5\">\n <Label htmlFor=\"knowledge-title\">Title</Label>\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <Input\n className=\"fk:max-w-md\"\n disabled={disabled}\n id=\"knowledge-title\"\n maxLength={KNOWLEDGE_MAX_TITLE_LENGTH}\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && titleChanged) {\n event.preventDefault();\n void save({ title: title.trim() });\n }\n }}\n />\n {titleChanged ? (\n <Button disabled={disabled} size=\"sm\" variant=\"outline\" onClick={() => void save({ title: title.trim() })}>\n Save\n </Button>\n ) : null}\n </div>\n <p className=\"fk:text-xs fk:text-muted-foreground\">The agent cites the document by this title.</p>\n </div>\n <label className=\"fk:flex fk:w-fit fk:cursor-pointer fk:items-center fk:gap-3\">\n <Switch\n checked={source.agentVisible}\n disabled={disabled}\n onCheckedChange={(checked) => void save({ agentVisible: checked })}\n />\n <span className=\"fk:flex fk:flex-col\">\n <span className=\"fk:text-sm fk:font-medium\">Visible to the agent</span>\n <span className=\"fk:text-xs fk:text-muted-foreground\">\n Off keeps the document in the list for people but out of the agent's searches.\n </span>\n </span>\n </label>\n <div className=\"fk:flex fk:flex-col fk:gap-2\">\n <span className=\"fk:text-sm fk:font-medium\">Spaces</span>\n <p className=\"fk:text-xs fk:text-muted-foreground\">\n {source.spaces.length === 0\n ? 'Every project member can read this document. Pick spaces to limit it to their members.'\n : 'Only members of the selected spaces (and the agent working for them) can read this document.'}\n </p>\n {selectableSpaces.length === 0 ? (\n <p className=\"fk:text-sm fk:text-muted-foreground\">{spacesEmptyMessage}</p>\n ) : (\n <div className=\"fk:flex fk:flex-wrap fk:gap-x-6 fk:gap-y-2\">\n {selectableSpaces.map((space) => (\n <label className=\"fk:flex fk:cursor-pointer fk:items-center fk:gap-2 fk:text-sm\" key={space.id}>\n <Checkbox\n checked={source.spaces.includes(space.code)}\n disabled={disabled}\n onCheckedChange={() => void save({ spaces: toggleSpaceCode(source.spaces, space.code) })}\n />\n {space.label}\n </label>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport function Source(): JSX.Element {\n const { api, projectId } = useProjectKnowledge();\n const { sourceId } = useParams<{ sourceId: string }>();\n const navigate = useNavigate();\n const canMutate = useCanMutate();\n const isViewing = useIsViewing();\n const [isBusy, setIsBusy] = useState(false);\n const [isReindexing, setIsReindexing] = useState(false);\n const { data, error, isLoading, mutate } = useSWR<KnowledgeSourceDetail>(\n projectId && sourceId ? knowledgePaths(projectId).source(sourceId) : null,\n fetcher,\n { refreshInterval: isViewing && isBusy ? DETAIL_POLL_INTERVAL_MS : 0 }\n );\n\n useEffect(() => {\n setIsBusy(data ? isKnowledgeSourceBusy(data.source, data.job) : false);\n }, [data]);\n\n if (!projectId || !api || !sourceId) {\n return <PageMessage>Select a document.</PageMessage>;\n }\n\n // A failed background refresh keeps the last good data on screen; only a\n // document that never loaded is reported as missing.\n if (error && !data) {\n return <PageMessage>This document does not exist or is not shared with you.</PageMessage>;\n }\n\n if (isLoading || !data) {\n return <SourceDetailSkeleton />;\n }\n\n const { job, source } = data;\n const status = summarizeKnowledgeStatus(source, job);\n const version = source.currentVersion;\n const isWorking = isReindexing;\n\n async function reindex(): Promise<void> {\n setIsReindexing(true);\n\n try {\n const result = await api!.reingestSource(source.id);\n\n toast.success('Re-indexing started.');\n await mutate({ job: result.job, source: { ...source, status: 'processing' } }, { revalidate: true });\n } catch (reindexError) {\n toast.error(describeApiError(reindexError, 'The document could not be re-indexed.'));\n } finally {\n setIsReindexing(false);\n }\n }\n\n const facts: { label: string; value: JSX.Element | string }[] = [\n { label: 'Type', value: getKnowledgeKindLabel(source) },\n ];\n\n if (source.originUrl) {\n facts.push({\n label: 'Address',\n value: (\n <a\n className=\"fk:inline-flex fk:items-center fk:gap-1 fk:underline fk:underline-offset-2\"\n href={source.originUrl}\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n <span className=\"fk:truncate\">{source.originUrl}</span>\n <ExternalLinkIcon className=\"fk:size-3.5 fk:shrink-0\" />\n </a>\n ),\n });\n }\n\n if (source.size !== null) {\n facts.push({ label: 'Size', value: formatFileSize(source.size) });\n }\n\n facts.push({ label: 'Added', value: formatDistance(new Date(source.createdAt), new Date(), { addSuffix: true }) });\n\n if (version?.publishedAt) {\n facts.push({\n label: 'Indexed',\n value: formatDistance(new Date(version.publishedAt), new Date(), { addSuffix: true }),\n });\n }\n\n return (\n <div className=\"fk:flex fk:h-full fk:min-h-0 fk:min-w-0 fk:flex-col fk:gap-3 fk:pb-3\">\n <SourcePageHeader\n actions={\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <PermissionTooltip disabled={!canMutate}>\n <Button\n disabled={!canMutate || isWorking || status.tone === 'busy'}\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void reindex()}\n >\n {isReindexing ? <LoaderCircle className=\"fk:animate-spin\" /> : <RefreshCwIcon />}\n Re-index\n </Button>\n </PermissionTooltip>\n <SourceActionsMenu\n isBusy={isWorking}\n source={source}\n trigger=\"page\"\n onRemoved={() => navigate('..', { relative: 'path' })}\n />\n </div>\n }\n title={source.title}\n />\n <div className=\"fk:min-h-0 fk:flex-1 fk:overflow-auto\">\n <div className=\"fk:mx-auto fk:flex fk:w-full fk:max-w-4xl fk:flex-col fk:gap-8 fk:py-2 fk:pl-4 fk:pr-6\">\n <section className=\"fk:flex fk:items-start fk:gap-4\">\n <SourceIcon source={source} />\n <div className=\"fk:flex fk:min-w-0 fk:flex-1 fk:flex-col fk:gap-2\">\n <div className=\"fk:flex fk:flex-wrap fk:items-center fk:gap-2\">\n <StatusBadge label={status.label} tone={status.tone} />\n <span className=\"fk:text-sm fk:text-muted-foreground\">{status.detail}</span>\n </div>\n {job?.error?.hint && (status.tone === 'error' || job.state === 'failed') ? (\n <p className=\"fk:text-sm fk:text-muted-foreground\">{job.error.hint}</p>\n ) : null}\n <dl className=\"fk:grid fk:grid-cols-[auto_1fr] fk:gap-x-4 fk:gap-y-1 fk:text-sm\">\n {facts.map((fact) => (\n <div className=\"fk:contents\" key={fact.label}>\n <dt className=\"fk:text-muted-foreground\">{fact.label}</dt>\n <dd className=\"fk:min-w-0 fk:truncate\">{fact.value}</dd>\n </div>\n ))}\n </dl>\n {version && version.warnings.length > 0 ? (\n <Alert>\n <AlertDescription>\n <ul className=\"fk:list-disc fk:pl-4\">\n {version.warnings.map((warning) => (\n <li key={warning}>{formatKnowledgeWarning(warning)}</li>\n ))}\n </ul>\n </AlertDescription>\n </Alert>\n ) : null}\n </div>\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <SectionTitle>Settings</SectionTitle>\n <SourceSettings\n api={api}\n projectId={projectId}\n source={source}\n onSaved={(saved) => void mutate({ job, source: saved }, { revalidate: false })}\n />\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <LinkedRecordsSection api={api} projectId={projectId} source={source} />\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <BookOpenIcon className=\"fk:size-4 fk:text-muted-foreground\" />\n <SectionTitle>Passages</SectionTitle>\n </div>\n <p className=\"fk:text-sm fk:text-muted-foreground\">\n The document is split into passages the agent searches and cites. Each one keeps its page, slide or\n section so a citation points back to the right place.\n </p>\n <PassageList projectId={projectId} source={source} />\n </section>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/apps/knowledge/source.tsx"],"names":["DETAIL_POLL_INTERVAL_MS","SourcePageHeader","actions","title","jsxs","Fragment","Tooltip","jsx","TooltipTrigger","SidebarTrigger","TooltipContent","Separator","Button","Link","ArrowLeft","SourceDetailSkeleton","Skeleton","SectionTitle","children","PassageList","projectId","source","version","passageCount","versionId","getPassagesKey","pageIndex","KNOWLEDGE_PASSAGES_PAGE_SIZE","from","knowledgePaths","pages","error","isLoading","setSize","size","useSWRInfinite","fetcher","passages","page","loaded","useEffect","passage","where","formatKnowledgeLocator","LoaderCircle","SourceSettings","api","onSaved","canMutate","useCanMutate","auth","useAuth","spacesData","useSWR","userSpaceCodes","projectSpaces","selectableSpaces","space","foreignSpaces","code","setTitle","useState","isSaving","setIsSaving","titleChanged","save","patch","result","invalidateKnowledgeLists","toast","describeApiError","disabled","spacesEmptyMessage","Alert","AlertDescription","Label","Input","KNOWLEDGE_MAX_TITLE_LENGTH","event","Switch","checked","Checkbox","toggleSpaceCode","Source","useProjectKnowledge","sourceId","useParams","navigate","useNavigate","isViewing","useIsViewing","isBusy","setIsBusy","isReindexing","setIsReindexing","data","mutate","isKnowledgeSourceBusy","PageMessage","job","status","summarizeKnowledgeStatus","isWorking","reindex","reindexError","facts","getKnowledgeKindLabel","ExternalLinkIcon","formatFileSize","formatDistance","PermissionTooltip","RefreshCwIcon","SourceActionsMenu","SourceIcon","StatusBadge","fact","warning","formatKnowledgeWarning","saved","LinkedRecordsSection","BookOpenIcon"],"mappings":"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","file":"source-MNHZQD4T.js","sourcesContent":["import type { JSX } from 'react';\nimport { useEffect, useState } from 'react';\nimport { formatDistance } from 'date-fns';\nimport { ArrowLeft, BookOpenIcon, ExternalLinkIcon, LoaderCircle, RefreshCwIcon } from 'lucide-react';\nimport { Link, useNavigate, useParams } from 'react-router-dom';\nimport useSWR from 'swr';\nimport useSWRInfinite from 'swr/infinite';\nimport { useAuth } from '../../auth/auth-context';\nimport { useIsViewing } from '../../core/apps/app-active';\nimport { useCanMutate } from '../../core/permissions';\nimport {\n Alert,\n AlertDescription,\n Button,\n Checkbox,\n Input,\n Label,\n PermissionTooltip,\n Separator,\n SidebarTrigger,\n Skeleton,\n Switch,\n toast,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../../ui';\nimport { fetcher, knowledgePaths, type KnowledgeApi, type ProjectSpace } from './api';\nimport {\n formatFileSize,\n formatKnowledgeLocator,\n formatKnowledgeWarning,\n getKnowledgeKindLabel,\n isKnowledgeSourceBusy,\n KNOWLEDGE_MAX_TITLE_LENGTH,\n KNOWLEDGE_PASSAGES_PAGE_SIZE,\n summarizeKnowledgeStatus,\n toggleSpaceCode,\n type KnowledgePassage,\n type KnowledgePassagesPage,\n type KnowledgeSource,\n type KnowledgeSourceDetail,\n} from './knowledge';\nimport { LinkedRecordsSection } from './record-links';\nimport {\n describeApiError,\n invalidateKnowledgeLists,\n PageMessage,\n SourceActionsMenu,\n SourceIcon,\n StatusBadge,\n useProjectKnowledge,\n} from './shared';\n\nconst DETAIL_POLL_INTERVAL_MS = 2_000;\n\nfunction SourcePageHeader({ actions, title }: { actions?: JSX.Element; title: string }): JSX.Element {\n return (\n <>\n <div className=\"fk:flex fk:shrink-0 fk:items-center fk:gap-2 fk:pr-4\">\n <Tooltip>\n <TooltipTrigger asChild>\n <SidebarTrigger className=\"fk:-ml-1 fk:h-4 fk:w-4\" />\n </TooltipTrigger>\n <TooltipContent>Toggle Sidebar</TooltipContent>\n </Tooltip>\n <Separator orientation=\"vertical\" className=\"fk:h-4\" />\n <h1 className=\"fk:min-w-0 fk:flex-1 fk:truncate fk:text-lg fk:font-semibold fk:leading-none fk:tracking-tight\">\n {title}\n </h1>\n {actions}\n </div>\n <Button asChild className=\"fk:w-fit fk:shrink-0\" size=\"sm\" variant=\"ghost\">\n <Link relative=\"path\" to=\"..\">\n <ArrowLeft className=\"fk:mr-2 fk:size-4\" />\n All documents\n </Link>\n </Button>\n </>\n );\n}\n\nfunction SourceDetailSkeleton(): JSX.Element {\n return (\n <div aria-busy=\"true\" className=\"fk:flex fk:flex-col fk:gap-6 fk:py-6 fk:pl-4 fk:pr-6\">\n <span className=\"fk:sr-only\">Loading document</span>\n <Skeleton className=\"fk:h-6 fk:w-64\" />\n <Skeleton className=\"fk:h-4 fk:w-96\" />\n <Skeleton className=\"fk:h-32 fk:w-full\" />\n </div>\n );\n}\n\nfunction SectionTitle({ children }: { children: string }): JSX.Element {\n return <h3 className=\"fk:text-sm fk:font-semibold fk:tracking-tight\">{children}</h3>;\n}\n\nfunction PassageList({ projectId, source }: { projectId: string; source: KnowledgeSource }): JSX.Element {\n const version = source.currentVersion?.status === 'published' ? source.currentVersion : null;\n const passageCount = version?.passageCount ?? 0;\n const versionId = version?.id ?? null;\n const getPassagesKey = (pageIndex: number): string | null => {\n if (!versionId || pageIndex * KNOWLEDGE_PASSAGES_PAGE_SIZE >= passageCount) {\n return null;\n }\n\n const from = pageIndex * KNOWLEDGE_PASSAGES_PAGE_SIZE;\n const path = knowledgePaths(projectId).passages(source.id, {\n from,\n to: Math.min(from + KNOWLEDGE_PASSAGES_PAGE_SIZE - 1, passageCount - 1),\n });\n\n // The version is part of the key, so a re-index swaps the pages instead\n // of serving the retired ones; the server ignores the extra parameter.\n return `${path}&version=${encodeURIComponent(versionId)}`;\n };\n const {\n data: pages,\n error,\n isLoading,\n setSize,\n size,\n } = useSWRInfinite<KnowledgePassagesPage>(getPassagesKey, fetcher, {\n revalidateFirstPage: false,\n });\n const passages: KnowledgePassage[] = pages?.flatMap((page) => page.passages) ?? [];\n const loaded = passages.length;\n\n // A new version starts from its first page again.\n useEffect(() => {\n void setSize(1);\n }, [setSize, versionId]);\n\n if (passageCount === 0) {\n return <p className=\"fk:text-sm fk:text-muted-foreground\">Passages appear here once the document is indexed.</p>;\n }\n\n if (error) {\n return <p className=\"fk:text-sm fk:text-destructive\">The passages could not be loaded.</p>;\n }\n\n return (\n <div className=\"fk:flex fk:flex-col fk:gap-3\">\n {passages.map((passage) => {\n const where = formatKnowledgeLocator(passage.locator);\n\n return (\n <article\n className=\"fk:rounded-lg fk:border fk:bg-background fk:px-4 fk:py-3 fk:corner-squircle\"\n key={passage.id}\n >\n <header className=\"fk:mb-1.5 fk:flex fk:items-center fk:gap-2 fk:text-xs fk:text-muted-foreground\">\n <span className=\"fk:font-medium\">#{String(passage.order + 1)}</span>\n {where ? <span className=\"fk:truncate\">{where}</span> : null}\n </header>\n <p className=\"fk:whitespace-pre-wrap fk:text-sm fk:leading-relaxed\">{passage.text}</p>\n </article>\n );\n })}\n {isLoading ? (\n <div className=\"fk:flex fk:items-center fk:gap-2 fk:py-2 fk:text-sm fk:text-muted-foreground\">\n <LoaderCircle className=\"fk:size-4 fk:animate-spin\" />\n Loading passages…\n </div>\n ) : null}\n {loaded < passageCount && !isLoading ? (\n <Button className=\"fk:w-fit\" size=\"sm\" variant=\"outline\" onClick={() => void setSize(size + 1)}>\n Show more ({String(loaded)} of {String(passageCount)})\n </Button>\n ) : null}\n </div>\n );\n}\n\nfunction SourceSettings({\n api,\n onSaved,\n projectId,\n source,\n}: {\n api: KnowledgeApi;\n onSaved: (_source: KnowledgeSource) => void;\n projectId: string;\n source: KnowledgeSource;\n}): JSX.Element {\n const canMutate = useCanMutate();\n const [, auth] = useAuth();\n const { data: spacesData } = useSWR<{ spaces: ProjectSpace[] }>(knowledgePaths(projectId).spaces, fetcher);\n const userSpaceCodes = auth.user?.spaces ?? [];\n // Only the caller's own spaces are offered: changing a source needs every\n // space it is shared with, and the server refuses codes the caller lacks.\n const projectSpaces = spacesData?.spaces ?? [];\n const selectableSpaces = projectSpaces.filter((space) => userSpaceCodes.includes(space.code));\n const foreignSpaces = source.spaces.filter((code) => !userSpaceCodes.includes(code));\n const [title, setTitle] = useState(source.title);\n const [isSaving, setIsSaving] = useState(false);\n const titleChanged = title.trim() !== source.title && title.trim().length > 0;\n\n useEffect(() => {\n setTitle(source.title);\n }, [source.title]);\n\n async function save(patch: { agentVisible?: boolean; spaces?: string[]; title?: string }): Promise<void> {\n if (!canMutate) {\n return;\n }\n\n setIsSaving(true);\n\n try {\n const result = await api.updateSource(source.id, patch);\n\n onSaved(result.source);\n void invalidateKnowledgeLists();\n } catch (error) {\n toast.error(describeApiError(error, 'The document could not be updated.'));\n } finally {\n setIsSaving(false);\n }\n }\n\n const disabled = !canMutate || isSaving || foreignSpaces.length > 0;\n let spacesEmptyMessage = 'This project has no spaces yet, so every member can read it.';\n\n if (projectSpaces.length > 0) {\n spacesEmptyMessage = 'You are not a member of any space in this project.';\n }\n\n return (\n <div className=\"fk:flex fk:flex-col fk:gap-5\">\n {foreignSpaces.length > 0 ? (\n <Alert>\n <AlertDescription>\n This document is shared with spaces you are not a member of ({foreignSpaces.join(', ')}), so only an owner\n or a member of all of them can change it.\n </AlertDescription>\n </Alert>\n ) : null}\n <div className=\"fk:flex fk:flex-col fk:gap-1.5\">\n <Label htmlFor=\"knowledge-title\">Title</Label>\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <Input\n className=\"fk:max-w-md\"\n disabled={disabled}\n id=\"knowledge-title\"\n maxLength={KNOWLEDGE_MAX_TITLE_LENGTH}\n value={title}\n onChange={(event) => setTitle(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter' && titleChanged) {\n event.preventDefault();\n void save({ title: title.trim() });\n }\n }}\n />\n {titleChanged ? (\n <Button disabled={disabled} size=\"sm\" variant=\"outline\" onClick={() => void save({ title: title.trim() })}>\n Save\n </Button>\n ) : null}\n </div>\n <p className=\"fk:text-xs fk:text-muted-foreground\">The agent cites the document by this title.</p>\n </div>\n <label className=\"fk:flex fk:w-fit fk:cursor-pointer fk:items-center fk:gap-3\">\n <Switch\n checked={source.agentVisible}\n disabled={disabled}\n onCheckedChange={(checked) => void save({ agentVisible: checked })}\n />\n <span className=\"fk:flex fk:flex-col\">\n <span className=\"fk:text-sm fk:font-medium\">Visible to the agent</span>\n <span className=\"fk:text-xs fk:text-muted-foreground\">\n Off keeps the document in the list for people but out of the agent's searches.\n </span>\n </span>\n </label>\n <div className=\"fk:flex fk:flex-col fk:gap-2\">\n <span className=\"fk:text-sm fk:font-medium\">Spaces</span>\n <p className=\"fk:text-xs fk:text-muted-foreground\">\n {source.spaces.length === 0\n ? 'Every project member can read this document. Pick spaces to limit it to their members.'\n : 'Only members of the selected spaces (and the agent working for them) can read this document.'}\n </p>\n {selectableSpaces.length === 0 ? (\n <p className=\"fk:text-sm fk:text-muted-foreground\">{spacesEmptyMessage}</p>\n ) : (\n <div className=\"fk:flex fk:flex-wrap fk:gap-x-6 fk:gap-y-2\">\n {selectableSpaces.map((space) => (\n <label className=\"fk:flex fk:cursor-pointer fk:items-center fk:gap-2 fk:text-sm\" key={space.id}>\n <Checkbox\n checked={source.spaces.includes(space.code)}\n disabled={disabled}\n onCheckedChange={() => void save({ spaces: toggleSpaceCode(source.spaces, space.code) })}\n />\n {space.label}\n </label>\n ))}\n </div>\n )}\n </div>\n </div>\n );\n}\n\nexport function Source(): JSX.Element {\n const { api, projectId } = useProjectKnowledge();\n const { sourceId } = useParams<{ sourceId: string }>();\n const navigate = useNavigate();\n const canMutate = useCanMutate();\n const isViewing = useIsViewing();\n const [isBusy, setIsBusy] = useState(false);\n const [isReindexing, setIsReindexing] = useState(false);\n const { data, error, isLoading, mutate } = useSWR<KnowledgeSourceDetail>(\n projectId && sourceId ? knowledgePaths(projectId).source(sourceId) : null,\n fetcher,\n { refreshInterval: isViewing && isBusy ? DETAIL_POLL_INTERVAL_MS : 0 }\n );\n\n useEffect(() => {\n setIsBusy(data ? isKnowledgeSourceBusy(data.source, data.job) : false);\n }, [data]);\n\n if (!projectId || !api || !sourceId) {\n return <PageMessage>Select a document.</PageMessage>;\n }\n\n // A failed background refresh keeps the last good data on screen; only a\n // document that never loaded is reported as missing.\n if (error && !data) {\n return <PageMessage>This document does not exist or is not shared with you.</PageMessage>;\n }\n\n if (isLoading || !data) {\n return <SourceDetailSkeleton />;\n }\n\n const { job, source } = data;\n const status = summarizeKnowledgeStatus(source, job);\n const version = source.currentVersion;\n const isWorking = isReindexing;\n\n async function reindex(): Promise<void> {\n setIsReindexing(true);\n\n try {\n const result = await api!.reingestSource(source.id);\n\n toast.success('Re-indexing started.');\n await mutate({ job: result.job, source: { ...source, status: 'processing' } }, { revalidate: true });\n } catch (reindexError) {\n toast.error(describeApiError(reindexError, 'The document could not be re-indexed.'));\n } finally {\n setIsReindexing(false);\n }\n }\n\n const facts: { label: string; value: JSX.Element | string }[] = [\n { label: 'Type', value: getKnowledgeKindLabel(source) },\n ];\n\n if (source.originUrl) {\n facts.push({\n label: 'Address',\n value: (\n <a\n className=\"fk:inline-flex fk:items-center fk:gap-1 fk:underline fk:underline-offset-2\"\n href={source.originUrl}\n rel=\"noreferrer\"\n target=\"_blank\"\n >\n <span className=\"fk:truncate\">{source.originUrl}</span>\n <ExternalLinkIcon className=\"fk:size-3.5 fk:shrink-0\" />\n </a>\n ),\n });\n }\n\n if (source.size !== null) {\n facts.push({ label: 'Size', value: formatFileSize(source.size) });\n }\n\n facts.push({ label: 'Added', value: formatDistance(new Date(source.createdAt), new Date(), { addSuffix: true }) });\n\n if (version?.publishedAt) {\n facts.push({\n label: 'Indexed',\n value: formatDistance(new Date(version.publishedAt), new Date(), { addSuffix: true }),\n });\n }\n\n return (\n <div className=\"fk:flex fk:h-full fk:min-h-0 fk:min-w-0 fk:flex-col fk:gap-3 fk:pb-3\">\n <SourcePageHeader\n actions={\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <PermissionTooltip disabled={!canMutate}>\n <Button\n disabled={!canMutate || isWorking || status.tone === 'busy'}\n size=\"sm\"\n variant=\"outline\"\n onClick={() => void reindex()}\n >\n {isReindexing ? <LoaderCircle className=\"fk:animate-spin\" /> : <RefreshCwIcon />}\n Re-index\n </Button>\n </PermissionTooltip>\n <SourceActionsMenu\n isBusy={isWorking}\n source={source}\n trigger=\"page\"\n onRemoved={() => navigate('..', { relative: 'path' })}\n />\n </div>\n }\n title={source.title}\n />\n <div className=\"fk:min-h-0 fk:flex-1 fk:overflow-auto\">\n <div className=\"fk:mx-auto fk:flex fk:w-full fk:max-w-4xl fk:flex-col fk:gap-8 fk:py-2 fk:pl-4 fk:pr-6\">\n <section className=\"fk:flex fk:items-start fk:gap-4\">\n <SourceIcon source={source} />\n <div className=\"fk:flex fk:min-w-0 fk:flex-1 fk:flex-col fk:gap-2\">\n <div className=\"fk:flex fk:flex-wrap fk:items-center fk:gap-2\">\n <StatusBadge label={status.label} tone={status.tone} />\n <span className=\"fk:text-sm fk:text-muted-foreground\">{status.detail}</span>\n </div>\n {job?.error?.hint && (status.tone === 'error' || job.state === 'failed') ? (\n <p className=\"fk:text-sm fk:text-muted-foreground\">{job.error.hint}</p>\n ) : null}\n <dl className=\"fk:grid fk:grid-cols-[auto_1fr] fk:gap-x-4 fk:gap-y-1 fk:text-sm\">\n {facts.map((fact) => (\n <div className=\"fk:contents\" key={fact.label}>\n <dt className=\"fk:text-muted-foreground\">{fact.label}</dt>\n <dd className=\"fk:min-w-0 fk:truncate\">{fact.value}</dd>\n </div>\n ))}\n </dl>\n {version && version.warnings.length > 0 ? (\n <Alert>\n <AlertDescription>\n <ul className=\"fk:list-disc fk:pl-4\">\n {version.warnings.map((warning) => (\n <li key={warning}>{formatKnowledgeWarning(warning)}</li>\n ))}\n </ul>\n </AlertDescription>\n </Alert>\n ) : null}\n </div>\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <SectionTitle>Settings</SectionTitle>\n <SourceSettings\n api={api}\n projectId={projectId}\n source={source}\n onSaved={(saved) => void mutate({ job, source: saved }, { revalidate: false })}\n />\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <LinkedRecordsSection api={api} projectId={projectId} source={source} />\n </section>\n <Separator />\n <section className=\"fk:flex fk:flex-col fk:gap-4\">\n <div className=\"fk:flex fk:items-center fk:gap-2\">\n <BookOpenIcon className=\"fk:size-4 fk:text-muted-foreground\" />\n <SectionTitle>Passages</SectionTitle>\n </div>\n <p className=\"fk:text-sm fk:text-muted-foreground\">\n The document is split into passages the agent searches and cites. Each one keeps its page, slide or\n section so a citation points back to the right place.\n </p>\n <PassageList projectId={projectId} source={source} />\n </section>\n </div>\n </div>\n </div>\n );\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@flexkit/studio",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.20",
|
|
4
4
|
"description": "Flexkit Studio - Build custom internal tools like PIMs, CRMs, and ERPs with a flexible React UI and a graph-backed API",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"flexkit",
|
|
@@ -167,8 +167,8 @@
|
|
|
167
167
|
"use-stick-to-bottom": "1.1.6",
|
|
168
168
|
"uuid": "^9.0.1",
|
|
169
169
|
"zod": "4.4.3",
|
|
170
|
-
"@flexkit/
|
|
171
|
-
"@flexkit/
|
|
170
|
+
"@flexkit/schema": "0.2.15",
|
|
171
|
+
"@flexkit/agent-protocol": "^0.3.11"
|
|
172
172
|
},
|
|
173
173
|
"peerDependencies": {
|
|
174
174
|
"react": "^19.0.0",
|
package/dist/root-B4D3C37Q.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import'./index.css';import {a as a$1}from'./chunk-QWQHXMXW.js';import {f as f$1,i,g as g$1,v,j,b as b$1,e as e$1,k,t,s,d,a,l,h,o as o$2,m,n,r as r$1,c as c$4,p,q as q$1}from'./chunk-ME55YNBF.js';import {c as c$2}from'./chunk-2DXR5NJV.js';import {c as c$1}from'./chunk-BMO7JFAX.js';import {c}from'./chunk-XMOSCJOI.js';import'./chunk-YDVO6XWD.js';import {a as a$2}from'./chunk-ERDARDGB.js';import {f}from'./chunk-H2RWSC56.js';import {g}from'./chunk-2HYQVMP3.js';import'./chunk-5CVDMZUI.js';import {K,M,Q,O,qa,N,R,S,s as s$1,T,V,W,X,o,P}from'./chunk-DGIY4SKN.js';import {e as e$2,g as g$2,h as h$1,j as j$1,q,r,s as s$2,o as o$1}from'./chunk-SZEGGBOC.js';import {v as v$1}from'./chunk-32ZU4MLE.js';import {b}from'./chunk-U45E5X3H.js';import'./chunk-HDOIOXMP.js';import {b as b$2,c as c$3,e}from'./chunk-USNXQOMJ.js';import {b as b$3}from'./chunk-6NRQMG26.js';import'./chunk-O2QMYUPS.js';import {useMemo,useRef,useState,useCallback,useEffect,useReducer}from'react';import {useLocation}from'react-router-dom';import Bt from'graphology';import Ft from'graphology-layout-forceatlas2';import Jt from'graphology-layout-forceatlas2/worker';import Yt,{DEFAULT_STYLES}from'sigma';import {jsxs,jsx}from'react/jsx-runtime';import {gql}from'@apollo/client';import {useApolloClient,useQuery}from'@apollo/client/react';import {formatDistance}from'date-fns';import {SearchIcon,ScanIcon,LoaderCircleIcon,ExpandIcon,EyeOffIcon,EraserIcon,XIcon,SquareArrowOutUpRightIcon}from'lucide-react';import {useDebounce}from'use-debounce';function ue(e){return Math.min(2e4,2e3+e*9)}function gt({mean:e,max:t,diagonal:n}){let r=Math.max(.05,n*.0015);return e<r&&t<r*20}var Qt=40,$t=400,Ut=1200,Vt=2;function Zt(e){return 5+Math.min(10,Math.sqrt(e)*2)}function bt(e){return Qt*(.8+Math.sqrt(e)*.6)}function yt(e,t,n){let r=Math.random()*Math.PI*2;return Array.from({length:t},(i,a)=>{let o=r+a/t*Math.PI*2+Math.random()*.3,b=n*(.9+Math.random()*.2);return {x:e.x+Math.cos(o)*b,y:e.y+Math.sin(o)*b}})}function St(e,t){return !Number.isNaN(e.getNodeAttribute(t,"x"))}function Kt(e,t){if(t.length===0)return {center:{x:0,y:0},reach:0};let n=t.reduce((i,a)=>({x:i.x+e.getNodeAttribute(a,"x"),y:i.y+e.getNodeAttribute(a,"y")}),{x:0,y:0});n.x/=t.length,n.y/=t.length;let r=t.reduce((i,a)=>Math.max(i,Math.hypot(e.getNodeAttribute(a,"x")-n.x,e.getNodeAttribute(a,"y")-n.y)),0);return {center:n,reach:r}}function Wt(e,t){let n=new Map;t.forEach(r=>{let i=e.neighbors(r).find(a=>!t.has(a)&&St(e,a))??null;n.set(i,[...n.get(i)??[],r]);}),n.forEach((r,i)=>{let a;if(i){let o={x:e.getNodeAttribute(i,"x"),y:e.getNodeAttribute(i,"y")};a=yt(o,r.length,bt(r.length));}else {let o=e.nodes().filter(A=>!t.has(A)&&St(e,A)),b=Kt(e,o);a=yt(b.center,r.length,b.reach+bt(r.length));}a.forEach((o,b)=>e.mergeNodeAttributes(r[b],o));});}var Ne=class{constructor(t){this.graph=t;this.positions=new Float64Array(t.order*2);let n=0;this.graph.forEachNode((r,i)=>{this.positions[n]=i.x,this.positions[n+1]=i.y,n+=2;});}positions;measure(){let{graph:t,positions:n}=this,r=0,i=0,a=0,o=Number.POSITIVE_INFINITY,b=Number.POSITIVE_INFINITY,A=Number.NEGATIVE_INFINITY,_=Number.NEGATIVE_INFINITY,f=0;return t.forEachNode((s,p)=>{let{x:E,y:S}=p;if(f+1<n.length&&!p.fixed){let x=Math.hypot(E-n[f],S-n[f+1]);r+=x,i=Math.max(i,x),a+=1;}n[f]=E,n[f+1]=S,f+=2,o=Math.min(o,E),b=Math.min(b,S),A=Math.max(A,E),_=Math.max(_,S);}),{mean:a>0?r/a:0,max:i,diagonal:t.order>0?Math.hypot(A-o,_-b):0}}};function en(e,t,n){let r=false,i=new Set,a=e.order>0;return e.forEachNode(o=>{t.nodes[o]||(e.dropNode(o),r=true);}),Object.values(t.nodes).forEach(o=>{e.hasNode(o.key)||(e.addNode(o.key,{entity:o.entity,label:o.label,color:n[o.entity]??"#71717a",size:5,x:Number.NaN,y:Number.NaN}),i.add(o.key),r=true);}),e.forEachEdge(o=>{t.edges[o]||(e.dropEdge(o),r=true);}),Object.values(t.edges).forEach(o=>{e.hasEdge(o.key)||(e.addEdgeWithKey(o.key,o.source,o.target,{size:1}),r=true);}),Wt(e,i),r&&e.forEachNode(o=>{e.setNodeAttribute(o,"size",Zt(e.degree(o)));}),{changed:r,added:i,hadNodes:a}}function xt({scene:e,colors:t,theme:n,apiRef:r,onSelect:i,onContextMenu:a,onExpand:o,onPin:b,onLayoutChange:A}){let _=useRef(null),f=useRef(null),s=useRef(null),p=useRef(null),E=useRef(null),S=useRef(null),x=useRef(null),c=useRef(null),N=useRef(null),d=useRef(new Set),C=useRef(e.pinned);C.current=e.pinned;let w=useRef({key:null,nodes:[]}),G=useRef({onSelect:i,onContextMenu:a,onExpand:o,onPin:b,onLayoutChange:A}),[T,Y]=useState(0);G.current={onSelect:i,onContextMenu:a,onExpand:o,onPin:b,onLayoutChange:A},f.current||(f.current=new Bt({type:"undirected",multi:true}));let M=useCallback(()=>{E.current!==null&&(window.clearTimeout(E.current),E.current=null),c.current!==null&&(window.clearInterval(c.current),c.current=null),p.current&&(p.current.kill(),p.current=null,N.current=null,G.current.onLayoutChange(false));let l=f.current;d.current.forEach(g=>{l?.hasNode(g)&&l.setNodeAttribute(g,"fixed",C.current[g]===true);}),d.current=new Set;},[]),F=useCallback((l,g=[])=>{let h=f.current;if(M(),!h||h.order===0)return;if(d.current=new Set(g.filter(k=>h.hasNode(k))),d.current.forEach(k=>h.setNodeAttribute(k,"fixed",true)),!h.someNode((k,P)=>!P.fixed)){M();return}let y=Ft.inferSettings(h),v=new Jt(h,{settings:{...y,adjustSizes:true,gravity:.2,slowDown:(y.slowDown??1)*2},outputReducer:(k,P)=>{let ne=S.current;return ne&&ne.node===k&&(P.x=ne.x,P.y=ne.y),P}}),D=performance.now(),X=new Ne(h),Q=false,z=0;p.current=v,N.current=D+l,v.start(),G.current.onLayoutChange(true);let u=()=>{S.current?(N.current=performance.now()+l,E.current=window.setTimeout(u,l)):M();};E.current=window.setTimeout(u,l),c.current=window.setInterval(()=>{let k=X.measure();if(S.current){z=0;return}Q=Q||k.max>0,z=Q&>(k)?z+1:0,z>=Vt&&performance.now()-D>=Ut&&M();},$t);},[M]),U=useCallback(l=>{let g=f.current,h=s.current;if(!g||!h)return;let y=w.current;if(h.setNodesState(y.nodes.filter(v=>g.hasNode(v)),{isNeighbour:false}),l&&g.hasNode(l)){let v=g.neighbors(l);h.setNodesState(v,{isNeighbour:true}),w.current={key:l,nodes:v};}else w.current={key:null,nodes:[]};},[]);return useEffect(()=>{let l=_.current,g=f.current;if(!l||!g)return;if(l.clientWidth===0||l.clientHeight===0){let u=new ResizeObserver(()=>{l.clientWidth>0&&l.clientHeight>0&&(u.disconnect(),Y(k=>k+1));});return u.observe(l),()=>u.disconnect()}let h=n==="dark",y=new Yt(g,l,{customNodeState:{isNeighbour:false},customEdgeState:{},customGraphState:{isDense:g.order>300,isZoomedIn:false},settings:{allowInvalidContainer:true,itemSizesReference:"screen",enableNodeDrag:true,renderEdgeLabels:false,labelRenderedSizeThreshold:7,labelDensity:.1,labelGridCellSize:80},styles:{nodes:[{...DEFAULT_STYLES.nodes,size:{whenState:"isHighlighted",then:u=>u.size+5,else:{whenState:"isHovered",then:u=>u.size+2,else:{attribute:"size"}}},cursor:"pointer",labelColor:h?"#e4e4e7":"#18181b",labelSize:12,labelFont:"ui-sans-serif, system-ui, sans-serif",labelVisibility:(u,k,P)=>k.isHovered||k.isHighlighted?"visible":P.isDense&&!P.isZoomedIn&&!k.isNeighbour?"hidden":"auto",backdropColor:h?"#27272a":"#ffffff",backdropShadowColor:h?"rgba(0, 0, 0, 0.6)":"rgba(0, 0, 0, 0.25)"}],edges:[{...DEFAULT_STYLES.edges,color:h?"#3f3f46":"#d4d4d8",size:1}]}});s.current=y,y.on("clickNode",({node:u})=>{G.current.onSelect(u);}),y.on("clickStage",()=>{G.current.onSelect(null);}),y.on("doubleClickNode",({node:u,event:k})=>{k.preventSigmaDefault(),G.current.onExpand(u);}),y.on("rightClickNode",({node:u,event:k})=>{k.preventSigmaDefault();let P=k.original;P.preventDefault(),G.current.onSelect(u),G.current.onContextMenu(u,{x:P.clientX,y:P.clientY});}),y.on("enterNode",({node:u})=>U(u)),y.on("leaveNode",()=>U(null));let v=u=>{let k=new Set([u,...g.neighbors(u)]);return g.nodes().filter(P=>P===u||!k.has(P))};y.on("nodeDragStart",({node:u})=>{S.current={node:u,x:g.getNodeAttribute(u,"x"),y:g.getNodeAttribute(u,"y")},g.size>0?(F(ue(g.order),v(u)),x.current=p.current):(M(),g.setNodeAttribute(u,"fixed",true));}),y.on("nodeDrag",({node:u})=>{S.current?.node===u&&(S.current.x=g.getNodeAttribute(u,"x"),S.current.y=g.getNodeAttribute(u,"y"));}),y.on("nodeDragEnd",({node:u})=>{let k=S.current!==null&&p.current!==null&&p.current===x.current;S.current=null,x.current=null,G.current.onPin(u),k&&F(ue(g.order),v(u));});let D=y.getCamera(),X=({ratio:u})=>{let k=u<.45;y.getGraphState().isZoomedIn!==k&&y.setGraphState({isZoomedIn:k});};D.on("updated",X);let Q=u=>u.preventDefault();l.addEventListener("contextmenu",Q);let z=new ResizeObserver(()=>{l.clientWidth>0&&l.clientHeight>0&&(y.resize(),y.scheduleRefresh());});return z.observe(l),r.current={fit:()=>{D.reset({duration:300});}},()=>{z.disconnect(),D.off("updated",X),l.removeEventListener("contextmenu",Q),r.current=null,s.current=null,w.current={key:null,nodes:[]},y.kill();}},[n,T,r,F,M,U]),useEffect(()=>{let l=f.current;if(!l)return;M();let{changed:g,added:h,hadNodes:y}=en(l,e,t);if(!g)return;if(s.current?.setGraphState({isDense:l.order>300}),U(l.hasNode(w.current.key??"")?w.current.key:null),l.size===0){M();return}let v=y&&h.size>0?l.nodes().filter(D=>!h.has(D)):[];F(ue(v.length>0?h.size:l.order),v);},[e.version]),useEffect(()=>{let l=f.current;l&&l.forEachNode((g,h)=>{l.setNodeAttribute(g,"color",t[h.entity]??"#71717a");});},[t]),useEffect(()=>{let l=f.current,g=s.current;if(!l||!g)return;let h=new Set(e.hiddenEntities),y=false;l.forEachNode((v,D)=>{g.setNodeState(v,{isHidden:h.has(D.entity),isHighlighted:v===e.selected});let X=e.pinned[v]===true||d.current.has(v);(D.fixed??false)!==X&&(l.setNodeAttribute(v,"fixed",X),y=true);}),y&&N.current!==null&&F(Math.max(500,N.current-performance.now()),[...d.current]),l.forEachEdge((v,D,X,Q)=>{g.setEdgeState(v,{isHidden:h.has(l.getNodeAttribute(X,"entity"))||h.has(l.getNodeAttribute(Q,"entity"))});});},[e.hiddenEntities,e.selected,e.pinned,e.version,T,n,F]),useEffect(()=>M,[M]),jsx("div",{className:"fk:h-full fk:w-full fk:min-h-0",ref:_})}function Nt({menu:e,relationships:t,isPinned:n,onClose:r$1,onExpandAll:i,onExpandAttribute:a,onHide:o,onHideOthers:b,onTogglePin:A,onOpenRecord:_}){let f=e?.key??"";return jsxs(e$2,{onOpenChange:s=>{s||r$1();},open:e!==null,children:[jsx(g$2,{asChild:true,children:jsx("span",{"aria-hidden":"true",className:"fk:fixed fk:size-0",style:{left:e?.x??0,top:e?.y??0}})}),jsxs(h$1,{align:"start",className:"fk:w-52","data-testid":"graph-context-menu",side:"bottom",children:[jsx(j$1,{onSelect:()=>i(f),children:"Expand all"}),t.length>0?jsxs(q,{children:[jsx(r,{children:"Expand"}),jsx(s$2,{className:"fk:max-h-80 fk:overflow-y-auto",children:t.map(s=>jsx(j$1,{onSelect:()=>a(f,s),children:s.label},s.name))})]}):null,jsx(o$1,{}),jsx(j$1,{onSelect:()=>o(f),children:"Hide"}),jsx(j$1,{onSelect:()=>b(f),children:"Hide others"}),jsx(j$1,{onSelect:()=>A(f),children:n?"Unpin position":"Pin position"}),jsx(o$1,{}),jsx(j$1,{onSelect:()=>_(f),children:"Open record"})]})]})}var ve={nodes:{},edges:{},counts:{},fetched:{},hiddenEntities:[],pinned:{},selected:null,notice:null,version:0};function nn(e,t){if(!t)return e;let n={...e};return Object.entries(t).forEach(([r,i])=>{n[r]={...n[r],...i};}),n}function rn(e,t){if(!t)return e;let n={...e};return Object.entries(t).forEach(([r,i])=>{let a={...n[r]};Object.entries(i).forEach(([o,b])=>{a[o]=Math.max(a[o]??0,b);}),n[r]=a;}),n}function Et(e,t){let n=Object.fromEntries(Object.entries(e.nodes).filter(([a])=>!t.has(a))),r=Object.fromEntries(Object.entries(e.edges).filter(([,a])=>!t.has(a.source)&&!t.has(a.target))),i=Object.fromEntries(Object.entries(e.pinned).filter(([a])=>!t.has(a)));return {...e,nodes:n,edges:r,pinned:i,selected:e.selected&&t.has(e.selected)?null:e.selected,version:e.version+1}}function vt(e,t){switch(t.type){case "merge":{let n={...e.nodes},r=Object.keys(n).length,i=0;t.data.nodes.forEach(o=>{if(!n[o.key]){if(r>=c$4){i+=1;return}n[o.key]=o,r+=1;}});let a={...e.edges};return t.data.edges.forEach(o=>{n[o.source]&&n[o.target]&&(a[o.key]=o);}),{...e,nodes:n,edges:a,counts:nn(e.counts,t.data.counts),fetched:rn(e.fetched,t.fetched),notice:i>0?`The canvas holds ${c$4.toLocaleString()} nodes at most; ${i.toLocaleString()} were left out. Hide some nodes to make room.`:e.notice,version:e.version+1}}case "remove":return Et(e,new Set(t.keys));case "keepOnly":{let n=new Set(t.keys);return Et(e,new Set(Object.keys(e.nodes).filter(r=>!n.has(r))))}case "clear":return {...ve,hiddenEntities:e.hiddenEntities,version:e.version+1};case "toggleEntity":return {...e,hiddenEntities:e.hiddenEntities.includes(t.entity)?e.hiddenEntities.filter(n=>n!==t.entity):[...e.hiddenEntities,t.entity]};case "select":return e.selected===t.key?e:{...e,selected:t.key};case "togglePin":{let n={...e.pinned};return n[t.key]?delete n[t.key]:n[t.key]=true,{...e,pinned:n}}case "notice":return {...e,notice:t.message};default:return e}}function At(e){return Object.values(e.nodes).reduce((t,n)=>(t[n.entity]=(t[n.entity]??0)+1,t),{})}function Ct(e,t){return Object.values(e.edges).reduce((n,r)=>(r.source===t?n[r.sourceAttribute]=(n[r.sourceAttribute]??0)+1:r.target===t&&(n[r.targetAttribute]=(n[r.targetAttribute]??0)+1),n),{})}function wt(e,t){return Object.values(e.edges).flatMap(n=>n.source===t?[n.target]:n.target===t?[n.source]:[])}function Gt({node:e$2,schema:t,scope:n$1,scene:r,colors:i,isLoading:a,onClose:o,onOpenRecord:b,onExpandAll:A,onExpandAttribute:_,onHide:f}){let s=g$1(t,e$2.entity),p=useMemo(()=>gql(s?o$2({entity:s,scope:n$1}):"query GraphDetails { __typename }"),[s,n$1]),E=useMemo(()=>gql(s?m({entity:s}):"query GraphCounts { __typename }"),[s]),S=useQuery(p,{variables:{id:e$2.id},skip:!s}),x=useQuery(E,{variables:{id:e$2.id},skip:!s}),c=s?S.data?.[s.plural]?.[0]:void 0,N=s?x.data?.[s.plural]?.[0]:void 0,d=useMemo(()=>Ct(r,e$2.key),[r,e$2.key]),C=s?e$1(s):[],w=s?n(s):[],G=c?._updatedAt?new Date(c._updatedAt):null;return jsxs("aside",{"aria-label":"Selected record",className:"fk:flex fk:w-72 fk:shrink-0 fk:flex-col fk:gap-5 fk:overflow-y-auto fk:border-l fk:bg-background fk:p-4 fk:text-sm","data-testid":"graph-inspector",children:[jsxs("div",{className:"fk:flex fk:flex-col fk:gap-2",children:[jsxs("div",{className:"fk:flex fk:items-center fk:justify-between fk:gap-2",children:[jsxs("span",{className:"fk:inline-flex fk:items-center fk:gap-1.5 fk:rounded-full fk:bg-muted fk:px-2 fk:py-0.5 fk:text-xs fk:font-medium",children:[jsx("span",{"aria-hidden":"true",className:"fk:size-2 fk:rounded-full",style:{backgroundColor:i[e$2.entity]??"#71717a"}}),s?h(s):e$2.entity]}),jsx(b$3,{"aria-label":"Close",className:"fk:size-7",onClick:o,size:"icon",variant:"ghost",children:jsx(XIcon,{className:"fk:size-4"})})]}),jsx("h2",{className:"fk:text-base fk:font-semibold fk:leading-snug fk:break-words",children:e$2.label}),jsxs("div",{className:"fk:flex fk:flex-wrap fk:gap-2",children:[jsxs(b$3,{className:"fk:h-8",onClick:()=>b(e$2.key),size:"sm",children:[jsx(SquareArrowOutUpRightIcon,{className:"fk:size-3.5"}),"Open record"]}),jsxs(b$2,{children:[jsx(c$3,{asChild:true,children:jsxs(b$3,{"aria-label":"Expand every relationship",className:"fk:h-8",disabled:a,onClick:()=>A(e$2.key),size:"sm",variant:"outline",children:[a?jsx(LoaderCircleIcon,{className:"fk:size-3.5 fk:animate-spin"}):jsx(ExpandIcon,{className:"fk:size-3.5"}),"Expand"]})}),jsx(e,{children:"Load the first related records of every relationship"})]}),jsxs(b$3,{"aria-label":"Hide this node",className:"fk:h-8",onClick:()=>f(e$2.key),size:"sm",variant:"outline",children:[jsx(EyeOffIcon,{className:"fk:size-3.5"}),"Hide"]})]})]}),jsxs("section",{className:"fk:flex fk:flex-col fk:gap-2",children:[jsx("h3",{className:"fk:text-xs fk:font-medium fk:text-muted-foreground",children:"Attributes"}),S.loading&&!c?jsx("span",{className:"fk:text-muted-foreground",children:"Loading\u2026"}):jsxs("dl",{className:"fk:grid fk:grid-cols-[minmax(0,2fr)_minmax(0,3fr)] fk:gap-x-3 fk:gap-y-1.5",children:[w.map(T=>jsxs("div",{className:"fk:contents",children:[jsx("dt",{className:"fk:truncate fk:text-muted-foreground",title:T.label,children:T.label}),jsx("dd",{className:"fk:min-w-0 fk:break-words",children:c&&r$1(c[T.name],n$1)||"\u2014"})]},T.name)),G?jsxs("div",{className:"fk:contents",children:[jsx("dt",{className:"fk:text-muted-foreground",children:"Updated"}),jsx("dd",{children:formatDistance(G,new Date,{addSuffix:true})})]}):null]})]}),C.length>0?jsxs("section",{className:"fk:flex fk:flex-col fk:gap-1",children:[jsx("h3",{className:"fk:mb-1 fk:text-xs fk:font-medium fk:text-muted-foreground",children:"Relationships"}),C.map(T=>{let Y=g$1(t,T.relationship?.entity??""),M=N?.[`${T.name}Connection`]?.aggregate?.count?.nodes,F=d[T.name]??0,U=r.fetched[e$2.key]?.[T.name]??0,l=typeof M=="number"&&U>=M;return jsxs("div",{className:"fk:flex fk:h-8 fk:items-center fk:gap-2",children:[jsx("span",{"aria-hidden":"true",className:"fk:size-2 fk:shrink-0 fk:rounded-full",style:{backgroundColor:i[T.relationship?.entity??""]??"#71717a"}}),jsx("span",{className:"fk:min-w-0 fk:flex-1 fk:truncate",title:Y?h(Y):void 0,children:T.label}),jsx("span",{className:"fk:text-xs fk:text-muted-foreground",children:typeof M=="number"?`${F} of ${M.toLocaleString()}`:F}),M===0||l?null:jsx(b$3,{className:"fk:h-6 fk:px-2 fk:text-xs",disabled:a,onClick:()=>_(e$2.key,T),size:"xs",variant:"outline",children:U>0?"More":"Expand"})]},T.name)})]}):null]})}var hn=250,kn=5;function bn(e,t){let n=t.trim();return !n||e.length===0?null:{searchRequests:{searches:e.map(r=>({collection:r.plural}))},commonParams:{q:n,limit:kn}}}function yn(e){let t=useMemo(()=>p(e),[e]),n=useMemo(()=>gql(t.length>0?q$1(t):"query GraphTotals { __typename }"),[t]),{data:r}=useQuery(n,{skip:t.length===0});return useMemo(()=>Object.fromEntries(t.map(i=>[i.plural,r?.[`${i.plural}Total`]]).filter(i=>typeof i[1]=="number")),[t,r])}function Tt({projectId:e,entities:t,colors:n,onCanvas:r,hiddenEntities:i,onStart:a,onHit:o$1,onToggleEntity:b}){let[A,_]=useState(""),[f]=useDebounce(A,hn),s=useMemo(()=>t.filter(d=>d.attributes.some(C=>C.searchable)),[t]),p=useMemo(()=>bn(s,f),[s,f]),{results:E,isLoading:S$1}=a$1(e,p),x=yn(t),c=useMemo(()=>new Map(t.map(d=>[d.name,d])),[t]),N$1=Object.keys(r).sort();return jsxs(N,{collapsible:"icon",variant:"inset",children:[jsxs(R,{children:[jsxs(S,{className:"fk:group-data-[collapsible=icon]:hidden",children:[jsxs("div",{className:"fk:relative",children:[jsx(SearchIcon,{className:"fk:pointer-events-none fk:absolute fk:left-2 fk:top-1/2 fk:size-4 fk:-translate-y-1/2 fk:text-muted-foreground"}),jsx(s$1,{"aria-label":"Search records to add to the canvas",className:"fk:h-8 fk:bg-background fk:pl-8 fk:shadow-none",onChange:d=>_(d.target.value),placeholder:s.length>0?"Search records\u2026":"No searchable entity",disabled:s.length===0,value:A})]}),p?jsxs("ul",{className:"fk:mt-2 fk:flex fk:flex-col fk:gap-0.5","data-testid":"graph-search-results",children:[E.map(d=>{let C=c.get(d._entityName),w=d[a$2(C)?.name??""];return jsx("li",{children:jsxs("button",{className:"fk:flex fk:w-full fk:items-center fk:gap-2 fk:rounded-md fk:px-2 fk:py-1.5 fk:text-left fk:text-sm fk:hover:bg-sidebar-accent",onClick:()=>o$1(d._entityName,d._id),type:"button",children:[jsx("span",{"aria-hidden":"true",className:"fk:size-2.5 fk:shrink-0 fk:rounded-full",style:{backgroundColor:n[d._entityName]??"#71717a"}}),jsx("span",{className:"fk:min-w-0 fk:flex-1 fk:truncate",children:String(w??d._id)})]})},`${d._entityName}:${d._id}`)}),!S$1&&E.length===0?jsx("li",{className:"fk:px-2 fk:py-1.5 fk:text-sm fk:text-muted-foreground",children:"Nothing found"}):null]}):null]}),jsxs(S,{children:[jsx(T,{children:"Start from"}),jsx(V,{children:t.map(d=>jsx(W,{children:jsxs(X,{onClick:()=>a(d),tooltip:h(d),children:[jsx("span",{"aria-hidden":"true",className:"fk:size-2.5 fk:shrink-0 fk:rounded-full",style:{backgroundColor:n[d.name]??"#71717a"}}),jsx("span",{className:"fk:truncate",children:h(d)}),x[d.plural]!==void 0?jsx("span",{className:"fk:ml-auto fk:text-xs fk:text-muted-foreground",children:x[d.plural]?.toLocaleString()}):null]})},d.name))})]}),N$1.length>0?jsxs(S,{className:"fk:group-data-[collapsible=icon]:hidden",children:[jsx(T,{children:"On canvas"}),jsx("ul",{className:"fk:flex fk:flex-col","data-testid":"graph-legend",children:N$1.map(d=>{let C=c.get(d),w=!i.includes(d),G=`graph-legend-${d}`;return jsxs("li",{className:"fk:flex fk:h-8 fk:items-center fk:gap-2 fk:px-2 fk:text-sm",children:[jsx("span",{"aria-hidden":"true",className:"fk:size-2.5 fk:shrink-0 fk:rounded-full",style:{backgroundColor:n[d]??"#71717a",opacity:w?1:.35}}),jsx("label",{className:"fk:min-w-0 fk:flex-1 fk:cursor-pointer fk:truncate",htmlFor:G,children:C?h(C):d}),jsx("span",{className:"fk:text-xs fk:text-muted-foreground",children:r[d]?.toLocaleString()}),jsx(o,{"aria-label":`Show ${C?h(C):d}`,checked:w,id:G,onCheckedChange:()=>b(d)})]},d)})})]}):null]}),jsx(P,{})]})}function fe({label:e$1,icon:t,disabled:n,onClick:r}){return jsxs(b$2,{children:[jsx(c$3,{asChild:true,children:jsxs(b$3,{className:"fk:h-8 fk:gap-1.5 fk:px-2.5",disabled:n,onClick:r,size:"sm",variant:"ghost",children:[t,jsx("span",{className:"fk:text-xs",children:e$1})]})}),jsx(e,{children:e$1})]})}function It({hasSelection:e,hasNodes:t,isLoading:n,onFit:r,onExpand:i,onHide:a,onClear:o}){return jsxs("div",{className:"fk:flex fk:items-center fk:gap-0.5 fk:rounded-lg fk:border fk:bg-background fk:p-1 fk:shadow-xs","data-testid":"graph-toolbar",children:[jsx(fe,{disabled:!t,icon:jsx(ScanIcon,{className:"fk:size-3.5"}),label:"Fit",onClick:r}),jsx(v$1,{className:"fk:mx-0.5 fk:h-4",orientation:"vertical"}),jsx(fe,{disabled:!e||n,icon:n?jsx(LoaderCircleIcon,{className:"fk:size-3.5 fk:animate-spin"}):jsx(ExpandIcon,{className:"fk:size-3.5"}),label:"Expand",onClick:i}),jsx(fe,{disabled:!e,icon:jsx(EyeOffIcon,{className:"fk:size-3.5"}),label:"Hide",onClick:a}),jsx(v$1,{className:"fk:mx-0.5 fk:h-4",orientation:"vertical"}),jsx(fe,{disabled:!t,icon:jsx(EraserIcon,{className:"fk:size-3.5"}),label:"Clear",onClick:o})]})}function Pt(e){return e instanceof Error?e.message:"The records could not be loaded."}function Ot({schema:e,scope:t$1}){let n=useApolloClient(),[r,i]=useReducer(vt,ve),[a$1,o]=useState(0),b=useCallback(async(f,s$1)=>{let p="ids"in s$1?s$1.ids:void 0,E="ids"in s$1?s$1.expand:false,S="limit"in s$1?s$1.limit:p?.length;o(x=>x+1);try{let c=(await n.query({query:gql(k({entity:f,schema:e,scope:t$1,expand:E})),variables:{where:p?{_id:{in:p}}:void 0,limit:S},fetchPolicy:"network-only"})).data?.[f.plural]??[];return i({type:"merge",data:s({records:c,entity:f,schema:e,scope:t$1}),fetched:t(c,f)}),c.map(N=>d(f.name,N._id))}catch(x){return qa.error(Pt(x)),[]}finally{o(x=>x-1);}},[n,e,t$1]),A=useCallback(async f=>{let s=r.nodes[f],p=s?g$1(e,s.entity):void 0;!s||!p||await b(p,{ids:[s.id],expand:true});},[b,e,r.nodes]),_=useCallback(async(f,s$1)=>{let p=r.nodes[f],E=p?g$1(e,p.entity):void 0;if(!p||!E)return;let S=r.fetched[f]?.[s$1.name]??0;o(x=>x+1);try{let c=(await n.query({query:gql(l({entity:E,schema:e,scope:t$1,attribute:s$1})),variables:{id:p.id,offset:S,limit:a},fetchPolicy:"network-only"})).data?.[E.plural]??[],N=c.reduce((d,C)=>{let w=C[s$1.name];return d+(Array.isArray(w)?w.length:0)},0);i({type:"merge",data:s({records:c,entity:E,schema:e,scope:t$1}),fetched:{[f]:{[s$1.name]:S+N}}});}catch(x){qa.error(Pt(x));}finally{o(x=>x-1);}},[n,e,t$1,r.fetched,r.nodes]);return {state:r,dispatch:i,isLoading:a$1>0,loadRecords:b,expandAll:A,expandAttribute:_}}function Hr(){let{currentProjectId:e$2,currentProject:t,currentProjectSchema:n}=f(),[,r]=g(),{scope:i$1}=c(),{resolvedTheme:a}=b(),o=useLocation(),b$3=c$1(),A=a==="dark"?"dark":"light",_=t?.scopes?.find(m=>m.isDefault)?.name??"default",f$2=i$1||_,s=r.user?.spaces,p=useMemo(()=>c$2(n,s),[n,s]),E=useMemo(()=>f$1(p),[p]),S=useMemo(()=>i(p,A),[p,A]),x=Ot({schema:p,scope:f$2}),{state:c$4,dispatch:N,isLoading:d,loadRecords:C,expandAll:w,expandAttribute:G}=x,T=useRef(null),[Y,M$1]=useState(null),[F,U]=useState(false),l=useRef(null),g$2=useMemo(()=>At(c$4),[c$4]),h=c$4.selected?c$4.nodes[c$4.selected]:void 0,y=Y?c$4.nodes[Y.key]:void 0,v$1=y?g$1(p,y.entity):void 0,D=Object.keys(c$4.nodes).length,X=Object.keys(c$4.edges).length,Q$1=K(),z=useCallback(m=>N({type:"select",key:m}),[N]),u=useCallback(m=>{let O=c$4.nodes[m],ee=O?g$1(p,O.entity):void 0;O&&ee&&b$3({type:"EditEntity",payload:{entityId:O.id,entityNamePlural:ee.plural}});},[b$3,p,c$4.nodes]),k=useCallback(m=>N({type:"remove",keys:[m]}),[N]),P=useCallback(m=>N({type:"keepOnly",keys:[m,...wt(c$4,m)]}),[N,c$4]),ne=useCallback(m=>N({type:"togglePin",key:m}),[N]),zt=useCallback(m=>{c$4.pinned[m]||N({type:"togglePin",key:m});},[N,c$4.pinned]),Ht=useCallback(async(m,O)=>{let ee=g$1(p,m);if(!ee)return;let[ae]=await C(ee,{ids:[O],expand:true});ae&&z(ae);},[C,p,z]),jt=useCallback((m,O)=>{M$1(null),G(m,O);},[G]);return useEffect(()=>{let m=v(o.search);if(!m||l.current===o.key)return;let O=g$1(p,m.entity);if(!O||p.length===0)return;l.current=o.key;let ee=m.ids.length>0?{ids:m.ids,expand:m.ids.length<=j}:{limit:b$1};C(O,ee).then(ae=>{m.ids.length===1&&ae[0]&&z(ae[0]);});},[o.key,o.search,p,C,z]),e$2?jsxs(M,{className:"fk:h-full",defaultOpen:Q$1,children:[jsx(Tt,{colors:S,entities:E,hiddenEntities:c$4.hiddenEntities,onCanvas:g$2,onHit:(m,O)=>{Ht(m,O);},onStart:m=>{C(m,{limit:b$1});},onToggleEntity:m=>N({type:"toggleEntity",entity:m}),projectId:e$2}),jsx(Q,{className:"fk:min-w-0",children:jsxs("div",{className:"fk:flex fk:h-full fk:min-h-0 fk:min-w-0","data-testid":"graph-app",children:[jsxs("div",{className:"fk:relative fk:min-w-0 fk:flex-1 fk:overflow-hidden fk:bg-background",children:[jsxs("div",{className:"fk:absolute fk:left-3 fk:top-3 fk:z-10 fk:flex fk:items-center fk:gap-2",children:[jsxs(b$2,{children:[jsx(c$3,{asChild:true,children:jsx(O,{className:"fk:h-8 fk:w-8 fk:rounded-lg fk:hover:bg-transparent fk:dark:hover:bg-transparent"})}),jsx(e,{children:"Toggle Sidebar"})]}),jsx(It,{hasNodes:D>0,hasSelection:h!==void 0,isLoading:d,onClear:()=>N({type:"clear"}),onExpand:()=>{c$4.selected&&w(c$4.selected);},onFit:()=>T.current?.fit(),onHide:()=>{c$4.selected&&k(c$4.selected);}})]}),D>0?null:jsx("div",{className:"fk:pointer-events-none fk:absolute fk:inset-0 fk:flex fk:items-center fk:justify-center fk:p-8 fk:text-center fk:text-sm fk:text-muted-foreground",children:d?"Loading records\u2026":"Search a record or start from an entity to draw its graph."}),jsx(xt,{apiRef:T,colors:S,onContextMenu:(m,O)=>M$1({key:m,...O}),onExpand:m=>{w(m);},onLayoutChange:U,onPin:zt,onSelect:z,scene:c$4,theme:A}),jsxs("div",{className:"fk:absolute fk:bottom-3 fk:left-3 fk:flex fk:max-w-[calc(100%-1.5rem)] fk:items-center fk:gap-2 fk:rounded-lg fk:border fk:bg-background fk:px-2.5 fk:py-1.5 fk:text-xs fk:text-muted-foreground fk:shadow-xs","data-testid":"graph-status",children:[jsxs("span",{children:[D.toLocaleString()," ",D===1?"node":"nodes"," \xB7 ",X.toLocaleString()," ",X===1?"relationship":"relationships"]}),F?jsx("span",{children:"\xB7 laying out\u2026"}):null,c$4.notice?jsxs("span",{className:"fk:truncate fk:text-foreground",children:["\xB7 ",c$4.notice]}):null]}),jsx(Nt,{isPinned:Y?c$4.pinned[Y.key]===true:false,menu:Y,onClose:()=>M$1(null),onExpandAll:m=>{w(m);},onExpandAttribute:jt,onHide:k,onHideOthers:P,onOpenRecord:u,onTogglePin:ne,relationships:v$1?e$1(v$1):[]})]}),h?jsx(Gt,{colors:S,isLoading:d,node:h,onClose:()=>z(null),onExpandAll:m=>{w(m);},onExpandAttribute:(m,O)=>{G(m,O);},onHide:k,onOpenRecord:u,scene:c$4,schema:p,scope:f$2}):null]})})]}):jsx("main",{className:"fk:flex fk:h-full fk:flex-1 fk:items-center fk:justify-center fk:p-8 fk:text-sm fk:text-muted-foreground",children:"Select a project to explore its graph."})}export{Hr as Root};//# sourceMappingURL=root-B4D3C37Q.js.map
|
|
2
|
-
//# sourceMappingURL=root-B4D3C37Q.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/apps/graph/layout.ts","../src/apps/graph/canvas.tsx","../src/apps/graph/context-menu.tsx","../src/apps/graph/scene.ts","../src/apps/graph/inspector.tsx","../src/apps/graph/sidebar.tsx","../src/apps/graph/toolbar.tsx","../src/apps/graph/use-scene.ts","../src/apps/graph/root.tsx"],"names":["layoutBudget","order","isSettled","mean","max","diagonal","threshold","PLACEMENT_RADIUS","SETTLE_INTERVAL_MS","SETTLE_MIN_MS","SETTLE_QUIET_SAMPLES","nodeSize","degree","ringRadius","count","ringPositions","center","radius","phase","_","index","angle","distance","isPositioned","graph","key","placedExtent","placed","sum","reach","placeNewNodes","added","groups","anchor","neighbour","keys","positions","extent","position","PositionTracker","cursor","_key","attributes","total","free","minX","minY","maxX","maxY","x","y","moved","syncGraph","scene","colors","changed","hadNodes","node","edge","GraphCanvas","theme","apiRef","onSelect","onContextMenu","onExpand","onPin","onLayoutChange","containerRef","useRef","graphRef","rendererRef","layoutRef","layoutTimerRef","dragRef","dragLayoutRef","settleTimerRef","layoutDeadlineRef","heldRef","pinnedRef","hoverRef","callbacksRef","mountAttempt","setMountAttempt","useState","Graph","stopLayout","useCallback","startLayout","budgetMs","hold","inferred","forceAtlas2","layout","FA2LayoutSupervisor","drag","startedAt","tracker","hasMoved","quietSamples","onBudget","movement","applyHover","renderer","previous","nodes","useEffect","container","observer","attempt","isDark","Sigma","DEFAULT_STYLES","_attributes","state","graphState","event","original","holdAllBut","wasRunning","camera","handleCameraUpdate","ratio","isZoomedIn","preventContextMenu","sizeObserver","hidden","pinsChanged","fixed","source","target","jsx","GraphContextMenu","menu","relationships","isPinned","onClose","onExpandAll","onExpandAttribute","onHide","onHideOthers","onTogglePin","onOpenRecord","jsxs","DropdownMenu","open","DropdownMenuTrigger","DropdownMenuContent","DropdownMenuItem","DropdownMenuSub","DropdownMenuSubTrigger","DropdownMenuSubContent","attribute","DropdownMenuSeparator","EMPTY_SCENE","mergeCounts","current","incoming","next","perAttribute","mergeFetched","merged","offset","withoutNodes","dropped","edges","pinned","sceneReducer","action","MAX_NODES","kept","entity","countNodesByEntity","result","countEdgesByAttribute","neighbourKeys","GraphInspector","schema","scope","isLoading","getEntity","detailsDocument","useMemo","gql","buildDetailsQuery","countsDocument","buildCountsQuery","details","useQuery","counts","record","countRecord","onCanvas","getRelationshipAttributes","getDetailAttributes","updatedAt","getEntityLabel","Button","XIcon","SquareArrowOutUpRightIcon","Tooltip","TooltipTrigger","LoaderCircleIcon","ExpandIcon","TooltipContent","EyeOffIcon","formatDetailValue","formatDistance","relatedEntity","shown","fetched","exhausted","SEARCH_DEBOUNCE_MS","SEARCH_HITS_PER_ENTITY","buildSearchRequest","entities","q","trimmed","useTotals","countable","getTotalEntities","document","buildTotalsQuery","data","pair","GraphSidebar","projectId","hiddenEntities","onStart","onHit","onToggleEntity","query","setQuery","debouncedQuery","useDebounce","searchable","request","results","useSearch","totals","entityByName","onCanvasEntities","Sidebar","SidebarContent","SidebarGroup","SearchIcon","Input","hit","label","getDisplayAttribute","SidebarGroupLabel","SidebarMenu","SidebarMenuItem","SidebarMenuButton","name","checked","id","Checkbox","SidebarRail","ToolbarButton","icon","disabled","onClick","GraphToolbar","hasSelection","hasNodes","onFit","onClear","ScanIcon","Separator","EraserIcon","errorMessage","error","useScene","client","useApolloClient","dispatch","useReducer","pending","setPending","loadRecords","selection","ids","expand","limit","records","buildRecordsQuery","graphFromRecords","fetchedFromRecords","nodeKey","toast","expandAll","expandAttribute","buildExpandQuery","EXPAND_PAGE","received","related","Root","currentProjectId","currentProject","currentProjectSchema","useConfig","auth","useAuth","useAppContext","resolvedTheme","useTheme","location","useLocation","dispatchAction","useDispatch","defaultScope","item","scopeField","userSpaces","filterEntitiesForSpaces","getGraphEntities","getEntityColors","canvasApi","setMenu","isLayoutRunning","setIsLayoutRunning","loadedSearchRef","selectedNode","menuNode","menuEntity","nodeCount","edgeCount","defaultOpen","readSidebarCookieState","select","openRecord","hide","hideOthers","togglePin","pin","addRecord","entityName","expandAttributeAndClose","params","parseGraphParams","EXPAND_HOP_MAX_RECORDS","SAMPLE_LIMIT","SidebarProvider","SidebarInset","SidebarTrigger"],"mappings":"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","file":"root-B4D3C37Q.js","sourcesContent":["/**\n * Pure layout rules of the canvas: how long the force layout may run, when\n * it counts as settled, and when a graph is too dense for labels everywhere.\n */\n\n/** Above this many nodes, labels show only around the pointer and the selection unless zoomed in. */\nexport const DENSE_NODES = 300;\n\n/** Camera ratio below which a dense graph shows labels again (1 = the whole graph in view). */\nexport const ZOOMED_IN_RATIO = 0.45;\n\n/** The longest the force layout runs after a change: 2 s for a few nodes, 20 s at the cap. */\nexport function layoutBudget(order: number): number {\n return Math.min(20000, 2000 + order * 9);\n}\n\n/** How much the free nodes moved since the last sample, and the graph's extent. */\nexport interface LayoutMovement {\n /** Mean move of the nodes the layout may move. */\n mean: number;\n /** Largest move of any of them: a few new nodes still flying in keep the layout going. */\n max: number;\n /** Bounding-box diagonal of the whole graph. */\n diagonal: number;\n}\n\n/**\n * Whether the layout has settled: the mean move per free node is a sliver\n * of the graph's extent and no node is still travelling, with a floor so a\n * tiny graph settles too.\n */\nexport function isSettled({ mean, max, diagonal }: LayoutMovement): boolean {\n const threshold = Math.max(0.05, diagonal * 0.0015);\n\n return mean < threshold && max < threshold * 20;\n}\n","'use client';\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { JSX, MutableRefObject } from 'react';\nimport Graph from 'graphology';\nimport type { Attributes } from 'graphology-types';\nimport forceAtlas2 from 'graphology-layout-forceatlas2';\nimport FA2LayoutSupervisor from 'graphology-layout-forceatlas2/worker';\nimport Sigma, { DEFAULT_STYLES } from 'sigma';\nimport { DENSE_NODES, isSettled, layoutBudget, ZOOMED_IN_RATIO, type LayoutMovement } from './layout';\nimport type { SceneState } from './scene';\n\ntype NodeAttributes = {\n entity: string;\n label: string;\n color: string;\n size: number;\n x: number;\n y: number;\n fixed?: boolean;\n};\ntype EdgeAttributes = { size: number };\n/** A neighbour of the hovered node, for its label. */\ntype NodeState = { isNeighbour: boolean };\ntype EdgeState = Record<string, never>;\n/** Too many nodes for labels everywhere; zoomed in far enough to show them anyway. */\ntype GraphState = { isDense: boolean; isZoomedIn: boolean };\ntype Renderer = Sigma<NodeAttributes, EdgeAttributes, Attributes, NodeState, EdgeState, GraphState>;\n\nexport interface GraphCanvasApi {\n /** Brings the whole graph into view. */\n fit: () => void;\n}\n\nexport interface GraphCanvasProps {\n scene: SceneState;\n colors: { [entity: string]: string };\n theme: 'light' | 'dark';\n apiRef: MutableRefObject<GraphCanvasApi | null>;\n onSelect: (key: string | null) => void;\n onContextMenu: (key: string, position: { x: number; y: number }) => void;\n onExpand: (key: string) => void;\n onPin: (key: string) => void;\n onLayoutChange: (running: boolean) => void;\n}\n\n/** Spread of new nodes around the node they came from, in graph units. */\nconst PLACEMENT_RADIUS = 40;\n/** How often the layout is checked for movement. */\nconst SETTLE_INTERVAL_MS = 400;\n/** The layout runs at least this long before it may be called settled. */\nconst SETTLE_MIN_MS = 1200;\n/** Two quiet samples in a row, after the worker first moved something, end the layout. */\nconst SETTLE_QUIET_SAMPLES = 2;\n\nfunction nodeSize(degree: number): number {\n return 5 + Math.min(10, Math.sqrt(degree) * 2);\n}\n\ntype Point = { x: number; y: number };\n\n/** The ring new nodes start on: wider the more of them share an anchor, so they do not explode apart. */\nfunction ringRadius(count: number): number {\n return PLACEMENT_RADIUS * (0.8 + Math.sqrt(count) * 0.6);\n}\n\n/**\n * Evenly spaced positions on a ring, with a little jitter so no two coincide\n * and a random phase so a lone newcomer can land on any side of its anchor.\n */\nfunction ringPositions(center: Point, count: number, radius: number): Point[] {\n const phase = Math.random() * Math.PI * 2;\n\n return Array.from({ length: count }, (_, index) => {\n const angle = phase + (index / count) * Math.PI * 2 + Math.random() * 0.3;\n const distance = radius * (0.9 + Math.random() * 0.2);\n\n return { x: center.x + Math.cos(angle) * distance, y: center.y + Math.sin(angle) * distance };\n });\n}\n\nfunction isPositioned(graph: Graph<NodeAttributes, EdgeAttributes>, key: string): boolean {\n return !Number.isNaN(graph.getNodeAttribute(key, 'x'));\n}\n\n/** Centre and reach of the nodes already placed, to put unanchored newcomers beyond them. */\nfunction placedExtent(\n graph: Graph<NodeAttributes, EdgeAttributes>,\n placed: string[]\n): { center: Point; reach: number } {\n if (placed.length === 0) {\n return { center: { x: 0, y: 0 }, reach: 0 };\n }\n\n const center = placed.reduce(\n (sum, key) => ({ x: sum.x + graph.getNodeAttribute(key, 'x'), y: sum.y + graph.getNodeAttribute(key, 'y') }),\n { x: 0, y: 0 }\n );\n center.x /= placed.length;\n center.y /= placed.length;\n const reach = placed.reduce(\n (max, key) =>\n Math.max(\n max,\n Math.hypot(graph.getNodeAttribute(key, 'x') - center.x, graph.getNodeAttribute(key, 'y') - center.y)\n ),\n 0\n );\n\n return { center, reach };\n}\n\n/**\n * Places new nodes: those sharing an anchor already on the canvas go on a\n * ring around it, the rest on a ring beyond everything placed so far.\n */\nfunction placeNewNodes(graph: Graph<NodeAttributes, EdgeAttributes>, added: Set<string>): void {\n const groups = new Map<string | null, string[]>();\n added.forEach((key) => {\n const anchor =\n graph.neighbors(key).find((neighbour) => !added.has(neighbour) && isPositioned(graph, neighbour)) ?? null;\n groups.set(anchor, [...(groups.get(anchor) ?? []), key]);\n });\n groups.forEach((keys, anchor) => {\n let positions: Point[];\n\n if (anchor) {\n const center = { x: graph.getNodeAttribute(anchor, 'x'), y: graph.getNodeAttribute(anchor, 'y') };\n positions = ringPositions(center, keys.length, ringRadius(keys.length));\n } else {\n const placed = graph.nodes().filter((key) => !added.has(key) && isPositioned(graph, key));\n const extent = placedExtent(graph, placed);\n positions = ringPositions(extent.center, keys.length, extent.reach + ringRadius(keys.length));\n }\n\n positions.forEach((position, index) => graph.mergeNodeAttributes(keys[index]!, position));\n });\n}\n\n/**\n * Positions of every node, kept in one typed array the layout's movement is\n * measured against: one pass per sample, no allocation.\n */\nclass PositionTracker {\n private positions: Float64Array;\n\n constructor(private readonly graph: Graph<NodeAttributes, EdgeAttributes>) {\n this.positions = new Float64Array(graph.order * 2);\n let cursor = 0;\n this.graph.forEachNode((_key, attributes) => {\n this.positions[cursor] = attributes.x;\n this.positions[cursor + 1] = attributes.y;\n cursor += 2;\n });\n }\n\n /** Movement since the last call, then remembers the current positions. */\n measure(): LayoutMovement {\n const { graph, positions } = this;\n let total = 0;\n let max = 0;\n let free = 0;\n let minX = Number.POSITIVE_INFINITY;\n let minY = Number.POSITIVE_INFINITY;\n let maxX = Number.NEGATIVE_INFINITY;\n let maxY = Number.NEGATIVE_INFINITY;\n let index = 0;\n graph.forEachNode((_key, attributes) => {\n const { x, y } = attributes;\n\n if (index + 1 < positions.length && !attributes.fixed) {\n const moved = Math.hypot(x - positions[index]!, y - positions[index + 1]!);\n total += moved;\n max = Math.max(max, moved);\n free += 1;\n }\n\n positions[index] = x;\n positions[index + 1] = y;\n index += 2;\n minX = Math.min(minX, x);\n minY = Math.min(minY, y);\n maxX = Math.max(maxX, x);\n maxY = Math.max(maxY, y);\n });\n\n return {\n mean: free > 0 ? total / free : 0,\n max,\n diagonal: graph.order > 0 ? Math.hypot(maxX - minX, maxY - minY) : 0,\n };\n }\n}\n\n/**\n * Adds the scene's new nodes and edges to the graph, drops the removed ones\n * and places new nodes around what is already on the canvas. Reports what\n * was added and whether anything was placed before.\n */\nfunction syncGraph(\n graph: Graph<NodeAttributes, EdgeAttributes>,\n scene: SceneState,\n colors: { [entity: string]: string }\n): { changed: boolean; added: Set<string>; hadNodes: boolean } {\n let changed = false;\n const added = new Set<string>();\n const hadNodes = graph.order > 0;\n\n graph.forEachNode((key) => {\n if (!scene.nodes[key]) {\n graph.dropNode(key);\n changed = true;\n }\n });\n Object.values(scene.nodes).forEach((node) => {\n if (graph.hasNode(node.key)) {\n return;\n }\n\n graph.addNode(node.key, {\n entity: node.entity,\n label: node.label,\n color: colors[node.entity] ?? '#71717a',\n size: 5,\n x: Number.NaN,\n y: Number.NaN,\n });\n added.add(node.key);\n changed = true;\n });\n graph.forEachEdge((key) => {\n if (!scene.edges[key]) {\n graph.dropEdge(key);\n changed = true;\n }\n });\n // A multigraph: two relationships between the same records are two edges.\n Object.values(scene.edges).forEach((edge) => {\n if (!graph.hasEdge(edge.key)) {\n graph.addEdgeWithKey(edge.key, edge.source, edge.target, { size: 1 });\n changed = true;\n }\n });\n\n placeNewNodes(graph, added);\n\n if (changed) {\n graph.forEachNode((key) => {\n graph.setNodeAttribute(key, 'size', nodeSize(graph.degree(key)));\n });\n }\n\n return { changed, added, hadNodes };\n}\n\n/**\n * The WebGL canvas: a graphology graph that lives as long as the component,\n * rendered by sigma and laid out by ForceAtlas2 in a web worker until it\n * settles after every change. Selection, hover, entity visibility and pins\n * are sigma states and node attributes; the scene stays the source of truth.\n */\nexport function GraphCanvas({\n scene,\n colors,\n theme,\n apiRef,\n onSelect,\n onContextMenu,\n onExpand,\n onPin,\n onLayoutChange,\n}: GraphCanvasProps): JSX.Element {\n const containerRef = useRef<HTMLDivElement>(null);\n const graphRef = useRef<Graph<NodeAttributes, EdgeAttributes> | null>(null);\n const rendererRef = useRef<Renderer | null>(null);\n const layoutRef = useRef<FA2LayoutSupervisor | null>(null);\n const layoutTimerRef = useRef<number | null>(null);\n /** The node under the pointer while one is dragged, with the pointer's graph position. */\n const dragRef = useRef<{ node: string; x: number; y: number } | null>(null);\n /** The layout a drag started, so a drop restarts only that one. */\n const dragLayoutRef = useRef<FA2LayoutSupervisor | null>(null);\n const settleTimerRef = useRef<number | null>(null);\n const layoutDeadlineRef = useRef<number | null>(null);\n /** Nodes held still for the running layout so only newcomers move. */\n const heldRef = useRef<Set<string>>(new Set());\n const pinnedRef = useRef<SceneState['pinned']>(scene.pinned);\n pinnedRef.current = scene.pinned;\n /** The hovered node and the neighbours marked around it. */\n const hoverRef = useRef<{ key: string | null; nodes: string[] }>({ key: null, nodes: [] });\n const callbacksRef = useRef({ onSelect, onContextMenu, onExpand, onPin, onLayoutChange });\n const [mountAttempt, setMountAttempt] = useState(0);\n callbacksRef.current = { onSelect, onContextMenu, onExpand, onPin, onLayoutChange };\n\n if (!graphRef.current) {\n graphRef.current = new Graph<NodeAttributes, EdgeAttributes>({ type: 'undirected', multi: true });\n }\n\n const stopLayout = useCallback((): void => {\n if (layoutTimerRef.current !== null) {\n window.clearTimeout(layoutTimerRef.current);\n layoutTimerRef.current = null;\n }\n\n if (settleTimerRef.current !== null) {\n window.clearInterval(settleTimerRef.current);\n settleTimerRef.current = null;\n }\n\n if (layoutRef.current) {\n layoutRef.current.kill();\n layoutRef.current = null;\n layoutDeadlineRef.current = null;\n callbacksRef.current.onLayoutChange(false);\n }\n\n const graph = graphRef.current;\n heldRef.current.forEach((key) => {\n if (graph?.hasNode(key)) {\n graph.setNodeAttribute(key, 'fixed', pinnedRef.current[key] === true);\n }\n });\n heldRef.current = new Set();\n }, []);\n\n // The worker reads `fixed` only when it (re)builds its matrices, so a new\n // supervisor is needed whenever pins change while a layout runs. The\n // layout stops once the nodes stop moving, or at the budget. Nodes in\n // `hold` stay where they are, so adding to a settled canvas moves only\n // the newcomers instead of shaking everything.\n const startLayout = useCallback(\n (budgetMs: number, hold: string[] = []): void => {\n const graph = graphRef.current;\n stopLayout();\n\n if (!graph || graph.order === 0) {\n return;\n }\n\n heldRef.current = new Set(hold.filter((key) => graph.hasNode(key)));\n heldRef.current.forEach((key) => graph.setNodeAttribute(key, 'fixed', true));\n\n // Nothing free to move (say, a dragged node without neighbours): a run would never settle.\n if (!graph.someNode((_key, attributes) => !attributes.fixed)) {\n stopLayout();\n\n return;\n }\n\n const inferred = forceAtlas2.inferSettings(graph);\n const layout = new FA2LayoutSupervisor(graph, {\n // Gentle gravity keeps loose parts near the rest; the extra slowdown keeps the motion calm.\n settings: { ...inferred, adjustSizes: true, gravity: 0.2, slowDown: (inferred.slowDown ?? 1) * 2 },\n // A dragged node stays under the pointer: the worker's positions are\n // overridden for it, and with a reducer set the supervisor reads the\n // graph's positions back into the worker, so the neighbours follow.\n outputReducer: (key: string, attributes: NodeAttributes): NodeAttributes => {\n const drag = dragRef.current;\n\n if (drag && drag.node === key) {\n attributes.x = drag.x;\n attributes.y = drag.y;\n }\n\n return attributes;\n },\n });\n const startedAt = performance.now();\n const tracker = new PositionTracker(graph);\n let hasMoved = false;\n let quietSamples = 0;\n layoutRef.current = layout;\n layoutDeadlineRef.current = startedAt + budgetMs;\n layout.start();\n callbacksRef.current.onLayoutChange(true);\n // While a node is dragged the layout runs on: the budget is extended and settling does not stop it.\n const onBudget = (): void => {\n if (dragRef.current) {\n layoutDeadlineRef.current = performance.now() + budgetMs;\n layoutTimerRef.current = window.setTimeout(onBudget, budgetMs);\n } else {\n stopLayout();\n }\n };\n layoutTimerRef.current = window.setTimeout(onBudget, budgetMs);\n settleTimerRef.current = window.setInterval(() => {\n const movement = tracker.measure();\n\n if (dragRef.current) {\n quietSamples = 0;\n\n return;\n }\n\n // The worker needs a moment to spawn; quiet samples before its first\n // positions arrive say nothing about the layout.\n hasMoved = hasMoved || movement.max > 0;\n quietSamples = hasMoved && isSettled(movement) ? quietSamples + 1 : 0;\n\n if (quietSamples >= SETTLE_QUIET_SAMPLES && performance.now() - startedAt >= SETTLE_MIN_MS) {\n stopLayout();\n }\n }, SETTLE_INTERVAL_MS);\n },\n [stopLayout]\n );\n\n /**\n * Marks the hovered node's neighbours so their labels show, clearing the\n * previous marks first. Re-run after the graph changes so nodes added\n * under the pointer are marked too, and marks of dropped nodes go away.\n */\n const applyHover = useCallback((key: string | null): void => {\n const graph = graphRef.current;\n const renderer = rendererRef.current;\n\n if (!graph || !renderer) {\n return;\n }\n\n const previous = hoverRef.current;\n renderer.setNodesState(\n previous.nodes.filter((node) => graph.hasNode(node)),\n { isNeighbour: false }\n );\n\n if (key && graph.hasNode(key)) {\n const nodes = graph.neighbors(key);\n renderer.setNodesState(nodes, { isNeighbour: true });\n hoverRef.current = { key, nodes };\n } else {\n hoverRef.current = { key: null, nodes: [] };\n }\n }, []);\n\n // The renderer: created per theme (styles are fixed at construction) over\n // the persistent graph.\n useEffect(() => {\n const container = containerRef.current;\n const graph = graphRef.current;\n\n if (!container || !graph) {\n return undefined;\n }\n\n // Sigma throws when the container has no size yet (first paint of a lazy\n // route, hidden app); wait for the box to get one before mounting.\n if (container.clientWidth === 0 || container.clientHeight === 0) {\n const observer = new ResizeObserver(() => {\n if (container.clientWidth > 0 && container.clientHeight > 0) {\n observer.disconnect();\n setMountAttempt((attempt) => attempt + 1);\n }\n });\n observer.observe(container);\n\n return () => observer.disconnect();\n }\n\n const isDark = theme === 'dark';\n const renderer: Renderer = new Sigma<NodeAttributes, EdgeAttributes, Attributes, NodeState, EdgeState, GraphState>(\n graph,\n container,\n {\n customNodeState: { isNeighbour: false },\n customEdgeState: {},\n customGraphState: { isDense: graph.order > DENSE_NODES, isZoomedIn: false },\n settings: {\n // Every render starts with a resize, which would throw while the\n // app is hidden but kept mounted; a hidden canvas renders at 1 px\n // instead and the size observer restores it when it shows again.\n allowInvalidContainer: true,\n itemSizesReference: 'screen',\n enableNodeDrag: true,\n renderEdgeLabels: false,\n labelRenderedSizeThreshold: 7,\n labelDensity: 0.1,\n labelGridCellSize: 80,\n },\n styles: {\n nodes: [\n {\n ...DEFAULT_STYLES.nodes,\n size: {\n whenState: 'isHighlighted',\n then: (attributes: NodeAttributes) => attributes.size + 5,\n else: {\n whenState: 'isHovered',\n then: (attributes: NodeAttributes) => attributes.size + 2,\n else: { attribute: 'size' },\n },\n },\n cursor: 'pointer',\n labelColor: isDark ? '#e4e4e7' : '#18181b',\n labelSize: 12,\n labelFont: 'ui-sans-serif, system-ui, sans-serif',\n // Dense graphs label only the pointer's surroundings and the\n // selection until zoomed in. Neighbours always go through the\n // label grid: a hub's many neighbours would otherwise pile up.\n labelVisibility: (_attributes, state, graphState) => {\n if (state.isHovered || state.isHighlighted) {\n return 'visible';\n }\n\n return graphState.isDense && !graphState.isZoomedIn && !state.isNeighbour ? 'hidden' : 'auto';\n },\n backdropColor: isDark ? '#27272a' : '#ffffff',\n backdropShadowColor: isDark ? 'rgba(0, 0, 0, 0.6)' : 'rgba(0, 0, 0, 0.25)',\n },\n ],\n edges: [\n {\n ...DEFAULT_STYLES.edges,\n color: isDark ? '#3f3f46' : '#d4d4d8',\n size: 1,\n },\n ],\n },\n }\n );\n rendererRef.current = renderer;\n\n renderer.on('clickNode', ({ node }) => {\n callbacksRef.current.onSelect(node);\n });\n renderer.on('clickStage', () => {\n callbacksRef.current.onSelect(null);\n });\n renderer.on('doubleClickNode', ({ node, event }) => {\n event.preventSigmaDefault();\n callbacksRef.current.onExpand(node);\n });\n renderer.on('rightClickNode', ({ node, event }) => {\n event.preventSigmaDefault();\n const original = event.original as MouseEvent;\n original.preventDefault();\n callbacksRef.current.onSelect(node);\n callbacksRef.current.onContextMenu(node, { x: original.clientX, y: original.clientY });\n });\n renderer.on('enterNode', ({ node }) => applyHover(node));\n renderer.on('leaveNode', () => applyHover(null));\n // Dragging a node pulls its neighbours along: the layout runs while the\n // drag lasts with the node held under the pointer, so a cluster can be\n // pulled apart. Everything else is held, so the rest of the canvas\n // stays still, and a canvas without relationships has nothing to pull on.\n const holdAllBut = (node: string): string[] => {\n const free = new Set([node, ...graph.neighbors(node)]);\n\n return graph.nodes().filter((key) => key === node || !free.has(key));\n };\n renderer.on('nodeDragStart', ({ node }) => {\n dragRef.current = { node, x: graph.getNodeAttribute(node, 'x'), y: graph.getNodeAttribute(node, 'y') };\n\n if (graph.size > 0) {\n startLayout(layoutBudget(graph.order), holdAllBut(node));\n dragLayoutRef.current = layoutRef.current;\n } else {\n stopLayout();\n graph.setNodeAttribute(node, 'fixed', true);\n }\n });\n renderer.on('nodeDrag', ({ node }) => {\n if (dragRef.current?.node === node) {\n dragRef.current.x = graph.getNodeAttribute(node, 'x');\n dragRef.current.y = graph.getNodeAttribute(node, 'y');\n }\n });\n renderer.on('nodeDragEnd', ({ node }) => {\n // A scene change during the drag replaced its layout with one settling\n // newcomers; that one keeps running, with the drop pinned by the scene.\n const wasRunning =\n dragRef.current !== null && layoutRef.current !== null && layoutRef.current === dragLayoutRef.current;\n dragRef.current = null;\n dragLayoutRef.current = null;\n callbacksRef.current.onPin(node);\n\n // The node stays where it was dropped while its neighbours settle around it.\n if (wasRunning) {\n startLayout(layoutBudget(graph.order), holdAllBut(node));\n }\n });\n\n const camera = renderer.getCamera();\n const handleCameraUpdate = ({ ratio }: { ratio: number }): void => {\n const isZoomedIn = ratio < ZOOMED_IN_RATIO;\n\n if (renderer.getGraphState().isZoomedIn !== isZoomedIn) {\n renderer.setGraphState({ isZoomedIn });\n }\n };\n camera.on('updated', handleCameraUpdate);\n\n const preventContextMenu = (event: MouseEvent): void => event.preventDefault();\n container.addEventListener('contextmenu', preventContextMenu);\n\n // Sigma only watches the window: the canvases must follow the container\n // when a pane opens beside it, or they keep their size and overflow it.\n const sizeObserver = new ResizeObserver(() => {\n if (container.clientWidth > 0 && container.clientHeight > 0) {\n renderer.resize();\n renderer.scheduleRefresh();\n }\n });\n sizeObserver.observe(container);\n\n apiRef.current = {\n fit: () => {\n void camera.reset({ duration: 300 });\n },\n };\n\n return () => {\n sizeObserver.disconnect();\n camera.off('updated', handleCameraUpdate);\n container.removeEventListener('contextmenu', preventContextMenu);\n apiRef.current = null;\n rendererRef.current = null;\n hoverRef.current = { key: null, nodes: [] };\n renderer.kill();\n };\n }, [theme, mountAttempt, apiRef, startLayout, stopLayout, applyHover]);\n\n // Scene changes: sync the graph, then let the layout settle the new nodes.\n useEffect(() => {\n const graph = graphRef.current;\n\n if (!graph) {\n return;\n }\n\n // The layout's supervisor respawns its worker on every graph change, on\n // a timer that outlives `kill()`: stop it before the graph is touched.\n stopLayout();\n const { changed, added, hadNodes } = syncGraph(graph, scene, colors);\n\n if (!changed) {\n return;\n }\n\n rendererRef.current?.setGraphState({ isDense: graph.order > DENSE_NODES });\n // Nodes added under the pointer get their hover marks; marks of dropped nodes go.\n applyHover(graph.hasNode(hoverRef.current.key ?? '') ? hoverRef.current.key : null);\n\n // Nothing to pull on: a bare sample stays on its ring.\n if (graph.size === 0) {\n stopLayout();\n\n return;\n }\n\n // Adding to a placed canvas: hold what is there, settle the newcomers.\n const hold = hadNodes && added.size > 0 ? graph.nodes().filter((key) => !added.has(key)) : [];\n startLayout(layoutBudget(hold.length > 0 ? added.size : graph.order), hold);\n // Nodes and edges only change with the scene version; colours are applied by their own effect.\n // eslint-disable-next-line react-hooks/exhaustive-deps -- see above\n }, [scene.version]);\n\n // Theme change: recolour the nodes.\n useEffect(() => {\n const graph = graphRef.current;\n\n if (!graph) {\n return;\n }\n\n graph.forEachNode((key, attributes) => {\n graph.setNodeAttribute(key, 'color', colors[attributes.entity] ?? '#71717a');\n });\n }, [colors]);\n\n // Selection, switched-off entities and pins.\n useEffect(() => {\n const graph = graphRef.current;\n const renderer = rendererRef.current;\n\n if (!graph || !renderer) {\n return;\n }\n\n const hidden = new Set(scene.hiddenEntities);\n let pinsChanged = false;\n graph.forEachNode((key, attributes) => {\n renderer.setNodeState(key, { isHidden: hidden.has(attributes.entity), isHighlighted: key === scene.selected });\n const fixed = scene.pinned[key] === true || heldRef.current.has(key);\n\n if ((attributes.fixed ?? false) !== fixed) {\n graph.setNodeAttribute(key, 'fixed', fixed);\n pinsChanged = true;\n }\n });\n\n // A pin change during a run restarts it with the same hold, so the\n // nodes kept still for it stay still.\n if (pinsChanged && layoutDeadlineRef.current !== null) {\n startLayout(Math.max(500, layoutDeadlineRef.current - performance.now()), [...heldRef.current]);\n }\n graph.forEachEdge((key, _attributes, source, target) => {\n renderer.setEdgeState(key, {\n isHidden:\n hidden.has(graph.getNodeAttribute(source, 'entity')) || hidden.has(graph.getNodeAttribute(target, 'entity')),\n });\n });\n }, [scene.hiddenEntities, scene.selected, scene.pinned, scene.version, mountAttempt, theme, startLayout]);\n\n // Unmount: stop the worker.\n useEffect(() => stopLayout, [stopLayout]);\n\n return <div className=\"fk:h-full fk:w-full fk:min-h-0\" ref={containerRef} />;\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport type { Attribute } from '../../core/types';\nimport {\n DropdownMenu,\n DropdownMenuContent,\n DropdownMenuItem,\n DropdownMenuSeparator,\n DropdownMenuSub,\n DropdownMenuSubContent,\n DropdownMenuSubTrigger,\n DropdownMenuTrigger,\n} from '../../ui';\n\nexport interface GraphContextMenuState {\n key: string;\n x: number;\n y: number;\n}\n\nexport interface GraphContextMenuProps {\n menu: GraphContextMenuState | null;\n relationships: Attribute[];\n isPinned: boolean;\n onClose: () => void;\n onExpandAll: (key: string) => void;\n onExpandAttribute: (key: string, attribute: Attribute) => void;\n onHide: (key: string) => void;\n onHideOthers: (key: string) => void;\n onTogglePin: (key: string) => void;\n onOpenRecord: (key: string) => void;\n}\n\n/** The right-click menu of a node, anchored at the pointer. */\nexport function GraphContextMenu({\n menu,\n relationships,\n isPinned,\n onClose,\n onExpandAll,\n onExpandAttribute,\n onHide,\n onHideOthers,\n onTogglePin,\n onOpenRecord,\n}: GraphContextMenuProps): JSX.Element {\n const key = menu?.key ?? '';\n\n return (\n <DropdownMenu\n onOpenChange={(open) => {\n if (!open) {\n onClose();\n }\n }}\n open={menu !== null}\n >\n <DropdownMenuTrigger asChild>\n <span\n aria-hidden=\"true\"\n className=\"fk:fixed fk:size-0\"\n style={{ left: menu?.x ?? 0, top: menu?.y ?? 0 }}\n />\n </DropdownMenuTrigger>\n <DropdownMenuContent align=\"start\" className=\"fk:w-52\" data-testid=\"graph-context-menu\" side=\"bottom\">\n <DropdownMenuItem onSelect={() => onExpandAll(key)}>Expand all</DropdownMenuItem>\n {relationships.length > 0 ? (\n <DropdownMenuSub>\n <DropdownMenuSubTrigger>Expand</DropdownMenuSubTrigger>\n <DropdownMenuSubContent className=\"fk:max-h-80 fk:overflow-y-auto\">\n {relationships.map((attribute) => (\n <DropdownMenuItem key={attribute.name} onSelect={() => onExpandAttribute(key, attribute)}>\n {attribute.label}\n </DropdownMenuItem>\n ))}\n </DropdownMenuSubContent>\n </DropdownMenuSub>\n ) : null}\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={() => onHide(key)}>Hide</DropdownMenuItem>\n <DropdownMenuItem onSelect={() => onHideOthers(key)}>Hide others</DropdownMenuItem>\n <DropdownMenuItem onSelect={() => onTogglePin(key)}>{isPinned ? 'Unpin position' : 'Pin position'}</DropdownMenuItem>\n <DropdownMenuSeparator />\n <DropdownMenuItem onSelect={() => onOpenRecord(key)}>Open record</DropdownMenuItem>\n </DropdownMenuContent>\n </DropdownMenu>\n );\n}\n","import { MAX_NODES, type GraphCounts, type GraphData, type GraphEdge, type GraphNode } from './graph';\n\n/**\n * The scene is what the canvas draws: the nodes and edges loaded so far,\n * which entities are switched off, which nodes are pinned, the selection.\n * A pure reducer so every rule is unit-tested; the canvas syncs to it.\n */\n\nexport interface SceneState {\n nodes: { [key: string]: GraphNode };\n edges: { [key: string]: GraphEdge };\n /** Total related records per relationship of a node, when the API told us. */\n counts: GraphCounts;\n /** Related records fetched so far per relationship of a node: the next page's offset. */\n fetched: GraphCounts;\n hiddenEntities: string[];\n pinned: { [key: string]: true };\n selected: string | null;\n /** A message for the status line, such as the node cap being reached. */\n notice: string | null;\n /** Bumped whenever nodes or edges change, so the canvas knows to sync. */\n version: number;\n}\n\nexport type SceneAction =\n | { type: 'merge'; data: GraphData; fetched?: GraphCounts }\n | { type: 'remove'; keys: string[] }\n | { type: 'keepOnly'; keys: string[] }\n | { type: 'clear' }\n | { type: 'toggleEntity'; entity: string }\n | { type: 'select'; key: string | null }\n | { type: 'togglePin'; key: string }\n | { type: 'notice'; message: string | null };\n\nexport const EMPTY_SCENE: SceneState = {\n nodes: {},\n edges: {},\n counts: {},\n fetched: {},\n hiddenEntities: [],\n pinned: {},\n selected: null,\n notice: null,\n version: 0,\n};\n\nfunction mergeCounts(current: GraphCounts, incoming: GraphCounts | undefined): GraphCounts {\n if (!incoming) {\n return current;\n }\n\n const next = { ...current };\n Object.entries(incoming).forEach(([key, perAttribute]) => {\n next[key] = { ...next[key], ...perAttribute };\n });\n\n return next;\n}\n\n/** Fetched offsets only move forward: a fresh first page never rewinds paging. */\nfunction mergeFetched(current: GraphCounts, incoming: GraphCounts | undefined): GraphCounts {\n if (!incoming) {\n return current;\n }\n\n const next = { ...current };\n Object.entries(incoming).forEach(([key, perAttribute]) => {\n const merged = { ...next[key] };\n Object.entries(perAttribute).forEach(([attribute, offset]) => {\n merged[attribute] = Math.max(merged[attribute] ?? 0, offset);\n });\n next[key] = merged;\n });\n\n return next;\n}\n\nfunction withoutNodes(state: SceneState, dropped: Set<string>): SceneState {\n const nodes = Object.fromEntries(Object.entries(state.nodes).filter(([key]) => !dropped.has(key)));\n const edges = Object.fromEntries(\n Object.entries(state.edges).filter(([, edge]) => !dropped.has(edge.source) && !dropped.has(edge.target))\n );\n const pinned = Object.fromEntries(Object.entries(state.pinned).filter(([key]) => !dropped.has(key)));\n\n return {\n ...state,\n nodes,\n edges,\n pinned,\n selected: state.selected && dropped.has(state.selected) ? null : state.selected,\n version: state.version + 1,\n };\n}\n\nexport function sceneReducer(state: SceneState, action: SceneAction): SceneState {\n switch (action.type) {\n case 'merge': {\n const nodes = { ...state.nodes };\n let count = Object.keys(nodes).length;\n let dropped = 0;\n\n action.data.nodes.forEach((node) => {\n if (nodes[node.key]) {\n return;\n }\n\n if (count >= MAX_NODES) {\n dropped += 1;\n\n return;\n }\n\n nodes[node.key] = node;\n count += 1;\n });\n\n const edges = { ...state.edges };\n action.data.edges.forEach((edge) => {\n if (nodes[edge.source] && nodes[edge.target]) {\n edges[edge.key] = edge;\n }\n });\n\n return {\n ...state,\n nodes,\n edges,\n counts: mergeCounts(state.counts, action.data.counts),\n fetched: mergeFetched(state.fetched, action.fetched),\n notice:\n dropped > 0\n ? `The canvas holds ${MAX_NODES.toLocaleString()} nodes at most; ${dropped.toLocaleString()} were left out. Hide some nodes to make room.`\n : state.notice,\n version: state.version + 1,\n };\n }\n case 'remove':\n return withoutNodes(state, new Set(action.keys));\n case 'keepOnly': {\n const kept = new Set(action.keys);\n\n return withoutNodes(state, new Set(Object.keys(state.nodes).filter((key) => !kept.has(key))));\n }\n case 'clear':\n return { ...EMPTY_SCENE, hiddenEntities: state.hiddenEntities, version: state.version + 1 };\n case 'toggleEntity':\n return {\n ...state,\n hiddenEntities: state.hiddenEntities.includes(action.entity)\n ? state.hiddenEntities.filter((entity) => entity !== action.entity)\n : [...state.hiddenEntities, action.entity],\n };\n case 'select':\n return state.selected === action.key ? state : { ...state, selected: action.key };\n case 'togglePin': {\n const pinned = { ...state.pinned };\n\n if (pinned[action.key]) {\n delete pinned[action.key];\n } else {\n pinned[action.key] = true;\n }\n\n return { ...state, pinned };\n }\n case 'notice':\n return { ...state, notice: action.message };\n default:\n return state;\n }\n}\n\n/** Nodes on the canvas per entity, for the legend. */\nexport function countNodesByEntity(state: SceneState): { [entity: string]: number } {\n return Object.values(state.nodes).reduce<{ [entity: string]: number }>((result, node) => {\n result[node.entity] = (result[node.entity] ?? 0) + 1;\n\n return result;\n }, {});\n}\n\n/** Related nodes of one node per relationship attribute that are on the canvas. */\nexport function countEdgesByAttribute(state: SceneState, key: string): { [attribute: string]: number } {\n return Object.values(state.edges).reduce<{ [attribute: string]: number }>((result, edge) => {\n if (edge.source === key) {\n result[edge.sourceAttribute] = (result[edge.sourceAttribute] ?? 0) + 1;\n } else if (edge.target === key) {\n result[edge.targetAttribute] = (result[edge.targetAttribute] ?? 0) + 1;\n }\n\n return result;\n }, {});\n}\n\n/** Keys of the nodes joined to one node by an edge. */\nexport function neighbourKeys(state: SceneState, key: string): string[] {\n return Object.values(state.edges).flatMap((edge) => {\n if (edge.source === key) {\n return [edge.target];\n }\n\n if (edge.target === key) {\n return [edge.source];\n }\n\n return [];\n });\n}\n","'use client';\n\nimport { useMemo } from 'react';\nimport type { JSX } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { formatDistance } from 'date-fns';\nimport { EyeOffIcon, ExpandIcon, LoaderCircleIcon, SquareArrowOutUpRightIcon, XIcon } from 'lucide-react';\nimport type { Attribute, Entity } from '../../core/types';\nimport { Button, Tooltip, TooltipContent, TooltipTrigger } from '../../ui';\nimport {\n buildCountsQuery,\n buildDetailsQuery,\n formatDetailValue,\n getDetailAttributes,\n getEntity,\n getEntityLabel,\n getRelationshipAttributes,\n type GraphNode,\n type GraphRecord,\n} from './graph';\nimport { countEdgesByAttribute, type SceneState } from './scene';\n\nexport interface GraphInspectorProps {\n node: GraphNode;\n schema: Entity[];\n scope: string;\n scene: SceneState;\n colors: { [entity: string]: string };\n isLoading: boolean;\n onClose: () => void;\n onOpenRecord: (key: string) => void;\n onExpandAll: (key: string) => void;\n onExpandAttribute: (key: string, attribute: Attribute) => void;\n onHide: (key: string) => void;\n}\n\ntype ConnectionCount = { aggregate?: { count?: { nodes?: number } } };\ntype DetailsResult = { [plural: string]: (GraphRecord & { _updatedAt?: string })[] };\n\n/**\n * The selected node: its scalar attributes in the current scope and each\n * relationship with how many related records are on the canvas out of the\n * total, with a button to fetch the next page.\n */\nexport function GraphInspector({\n node,\n schema,\n scope,\n scene,\n colors,\n isLoading,\n onClose,\n onOpenRecord,\n onExpandAll,\n onExpandAttribute,\n onHide,\n}: GraphInspectorProps): JSX.Element {\n const entity = getEntity(schema, node.entity);\n const detailsDocument = useMemo(\n () => gql(entity ? buildDetailsQuery({ entity, scope }) : 'query GraphDetails { __typename }'),\n [entity, scope]\n );\n const countsDocument = useMemo(\n () => gql(entity ? buildCountsQuery({ entity }) : 'query GraphCounts { __typename }'),\n [entity]\n );\n const details = useQuery<DetailsResult>(detailsDocument, { variables: { id: node.id }, skip: !entity });\n const counts = useQuery<{ [plural: string]: { [field: string]: ConnectionCount }[] }>(countsDocument, {\n variables: { id: node.id },\n skip: !entity,\n });\n const record = entity ? details.data?.[entity.plural]?.[0] : undefined;\n const countRecord = entity ? counts.data?.[entity.plural]?.[0] : undefined;\n const onCanvas = useMemo(() => countEdgesByAttribute(scene, node.key), [scene, node.key]);\n const relationships = entity ? getRelationshipAttributes(entity) : [];\n const attributes = entity ? getDetailAttributes(entity) : [];\n const updatedAt = record?._updatedAt ? new Date(record._updatedAt) : null;\n\n return (\n <aside\n aria-label=\"Selected record\"\n className=\"fk:flex fk:w-72 fk:shrink-0 fk:flex-col fk:gap-5 fk:overflow-y-auto fk:border-l fk:bg-background fk:p-4 fk:text-sm\"\n data-testid=\"graph-inspector\"\n >\n <div className=\"fk:flex fk:flex-col fk:gap-2\">\n <div className=\"fk:flex fk:items-center fk:justify-between fk:gap-2\">\n <span className=\"fk:inline-flex fk:items-center fk:gap-1.5 fk:rounded-full fk:bg-muted fk:px-2 fk:py-0.5 fk:text-xs fk:font-medium\">\n <span\n aria-hidden=\"true\"\n className=\"fk:size-2 fk:rounded-full\"\n style={{ backgroundColor: colors[node.entity] ?? '#71717a' }}\n />\n {entity ? getEntityLabel(entity) : node.entity}\n </span>\n <Button aria-label=\"Close\" className=\"fk:size-7\" onClick={onClose} size=\"icon\" variant=\"ghost\">\n <XIcon className=\"fk:size-4\" />\n </Button>\n </div>\n <h2 className=\"fk:text-base fk:font-semibold fk:leading-snug fk:break-words\">{node.label}</h2>\n <div className=\"fk:flex fk:flex-wrap fk:gap-2\">\n <Button className=\"fk:h-8\" onClick={() => onOpenRecord(node.key)} size=\"sm\">\n <SquareArrowOutUpRightIcon className=\"fk:size-3.5\" />\n Open record\n </Button>\n <Tooltip>\n <TooltipTrigger asChild>\n <Button\n aria-label=\"Expand every relationship\"\n className=\"fk:h-8\"\n disabled={isLoading}\n onClick={() => onExpandAll(node.key)}\n size=\"sm\"\n variant=\"outline\"\n >\n {isLoading ? <LoaderCircleIcon className=\"fk:size-3.5 fk:animate-spin\" /> : <ExpandIcon className=\"fk:size-3.5\" />}\n Expand\n </Button>\n </TooltipTrigger>\n <TooltipContent>Load the first related records of every relationship</TooltipContent>\n </Tooltip>\n <Button aria-label=\"Hide this node\" className=\"fk:h-8\" onClick={() => onHide(node.key)} size=\"sm\" variant=\"outline\">\n <EyeOffIcon className=\"fk:size-3.5\" />\n Hide\n </Button>\n </div>\n </div>\n\n <section className=\"fk:flex fk:flex-col fk:gap-2\">\n <h3 className=\"fk:text-xs fk:font-medium fk:text-muted-foreground\">Attributes</h3>\n {details.loading && !record ? (\n <span className=\"fk:text-muted-foreground\">Loading…</span>\n ) : (\n <dl className=\"fk:grid fk:grid-cols-[minmax(0,2fr)_minmax(0,3fr)] fk:gap-x-3 fk:gap-y-1.5\">\n {attributes.map((attribute) => (\n <div className=\"fk:contents\" key={attribute.name}>\n <dt className=\"fk:truncate fk:text-muted-foreground\" title={attribute.label}>\n {attribute.label}\n </dt>\n <dd className=\"fk:min-w-0 fk:break-words\">{record ? formatDetailValue(record[attribute.name], scope) || '—' : '—'}</dd>\n </div>\n ))}\n {updatedAt ? (\n <div className=\"fk:contents\">\n <dt className=\"fk:text-muted-foreground\">Updated</dt>\n <dd>{formatDistance(updatedAt, new Date(), { addSuffix: true })}</dd>\n </div>\n ) : null}\n </dl>\n )}\n </section>\n\n {relationships.length > 0 ? (\n <section className=\"fk:flex fk:flex-col fk:gap-1\">\n <h3 className=\"fk:mb-1 fk:text-xs fk:font-medium fk:text-muted-foreground\">Relationships</h3>\n {relationships.map((attribute) => {\n const relatedEntity = getEntity(schema, attribute.relationship?.entity ?? '');\n const total = countRecord?.[`${attribute.name}Connection`]?.aggregate?.count?.nodes;\n const shown = onCanvas[attribute.name] ?? 0;\n const fetched = scene.fetched[node.key]?.[attribute.name] ?? 0;\n const exhausted = typeof total === 'number' && fetched >= total;\n\n return (\n <div className=\"fk:flex fk:h-8 fk:items-center fk:gap-2\" key={attribute.name}>\n <span\n aria-hidden=\"true\"\n className=\"fk:size-2 fk:shrink-0 fk:rounded-full\"\n style={{ backgroundColor: colors[attribute.relationship?.entity ?? ''] ?? '#71717a' }}\n />\n <span className=\"fk:min-w-0 fk:flex-1 fk:truncate\" title={relatedEntity ? getEntityLabel(relatedEntity) : undefined}>\n {attribute.label}\n </span>\n <span className=\"fk:text-xs fk:text-muted-foreground\">\n {typeof total === 'number' ? `${shown} of ${total.toLocaleString()}` : shown}\n </span>\n {total === 0 || exhausted ? null : (\n <Button\n className=\"fk:h-6 fk:px-2 fk:text-xs\"\n disabled={isLoading}\n onClick={() => onExpandAttribute(node.key, attribute)}\n size=\"xs\"\n variant=\"outline\"\n >\n {fetched > 0 ? 'More' : 'Expand'}\n </Button>\n )}\n </div>\n );\n })}\n </section>\n ) : null}\n </aside>\n );\n}\n","'use client';\n\nimport { useMemo, useState } from 'react';\nimport type { JSX } from 'react';\nimport { gql } from '@apollo/client';\nimport { useQuery } from '@apollo/client/react';\nimport { SearchIcon } from 'lucide-react';\nimport { useDebounce } from 'use-debounce';\nimport { getDisplayAttribute } from '../../core/get-display-attribute';\nimport { useSearch } from '../../core/use-search';\nimport type { Entity, SearchRequestProps } from '../../core/types';\nimport {\n Checkbox,\n Input,\n SidebarContent,\n SidebarGroup,\n SidebarGroupLabel,\n SidebarMenu,\n SidebarMenuButton,\n SidebarMenuItem,\n SidebarPanel,\n SidebarRail,\n} from '../../ui';\nimport { buildTotalsQuery, getEntityLabel, getTotalEntities } from './graph';\n\nconst SEARCH_DEBOUNCE_MS = 250;\nconst SEARCH_HITS_PER_ENTITY = 5;\n\nexport interface GraphSidebarProps {\n projectId: string;\n entities: Entity[];\n colors: { [entity: string]: string };\n /** Nodes on the canvas per entity. */\n onCanvas: { [entity: string]: number };\n hiddenEntities: string[];\n onStart: (entity: Entity) => void;\n onHit: (entityName: string, id: string) => void;\n onToggleEntity: (entityName: string) => void;\n}\n\nfunction buildSearchRequest(entities: Entity[], q: string): SearchRequestProps | null {\n const trimmed = q.trim();\n\n if (!trimmed || entities.length === 0) {\n return null;\n }\n\n return {\n searchRequests: { searches: entities.map((entity) => ({ collection: entity.plural })) },\n commonParams: { q: trimmed, limit: SEARCH_HITS_PER_ENTITY },\n };\n}\n\n/** Count-store totals per entity for the \"Start from\" list; absent for space-bound entities. */\nfunction useTotals(entities: Entity[]): { [plural: string]: number } {\n const countable = useMemo(() => getTotalEntities(entities), [entities]);\n const document = useMemo(() => gql(countable.length > 0 ? buildTotalsQuery(countable) : 'query GraphTotals { __typename }'), [countable]);\n const { data } = useQuery<{ [field: string]: number }>(document, { skip: countable.length === 0 });\n\n return useMemo(\n () =>\n Object.fromEntries(\n countable\n .map((entity) => [entity.plural, data?.[`${entity.plural}Total`]] as const)\n .filter((pair): pair is readonly [string, number] => typeof pair[1] === 'number')\n ),\n [countable, data]\n );\n}\n\n/**\n * Search a record to add it to the canvas, start from a whole entity, and the\n * legend of what is on the canvas with a switch per entity.\n */\nexport function GraphSidebar({\n projectId,\n entities,\n colors,\n onCanvas,\n hiddenEntities,\n onStart,\n onHit,\n onToggleEntity,\n}: GraphSidebarProps): JSX.Element {\n const [query, setQuery] = useState('');\n const [debouncedQuery] = useDebounce(query, SEARCH_DEBOUNCE_MS);\n const searchable = useMemo(\n () => entities.filter((entity) => entity.attributes.some((attribute) => attribute.searchable)),\n [entities]\n );\n const request = useMemo(() => buildSearchRequest(searchable, debouncedQuery), [searchable, debouncedQuery]);\n const { results, isLoading } = useSearch(projectId, request);\n const totals = useTotals(entities);\n const entityByName = useMemo(() => new Map(entities.map((entity) => [entity.name, entity])), [entities]);\n const onCanvasEntities = Object.keys(onCanvas).sort();\n\n return (\n <SidebarPanel collapsible=\"icon\" variant=\"inset\">\n <SidebarContent>\n <SidebarGroup className=\"fk:group-data-[collapsible=icon]:hidden\">\n <div className=\"fk:relative\">\n <SearchIcon className=\"fk:pointer-events-none fk:absolute fk:left-2 fk:top-1/2 fk:size-4 fk:-translate-y-1/2 fk:text-muted-foreground\" />\n <Input\n aria-label=\"Search records to add to the canvas\"\n className=\"fk:h-8 fk:bg-background fk:pl-8 fk:shadow-none\"\n onChange={(event) => setQuery(event.target.value)}\n placeholder={searchable.length > 0 ? 'Search records…' : 'No searchable entity'}\n disabled={searchable.length === 0}\n value={query}\n />\n </div>\n {request ? (\n <ul className=\"fk:mt-2 fk:flex fk:flex-col fk:gap-0.5\" data-testid=\"graph-search-results\">\n {results.map((hit) => {\n const entity = entityByName.get(hit._entityName);\n const label = hit[getDisplayAttribute(entity)?.name ?? ''];\n\n return (\n <li key={`${hit._entityName}:${hit._id}`}>\n <button\n className=\"fk:flex fk:w-full fk:items-center fk:gap-2 fk:rounded-md fk:px-2 fk:py-1.5 fk:text-left fk:text-sm fk:hover:bg-sidebar-accent\"\n onClick={() => onHit(hit._entityName, hit._id)}\n type=\"button\"\n >\n <span\n aria-hidden=\"true\"\n className=\"fk:size-2.5 fk:shrink-0 fk:rounded-full\"\n style={{ backgroundColor: colors[hit._entityName] ?? '#71717a' }}\n />\n <span className=\"fk:min-w-0 fk:flex-1 fk:truncate\">{String(label ?? hit._id)}</span>\n </button>\n </li>\n );\n })}\n {!isLoading && results.length === 0 ? (\n <li className=\"fk:px-2 fk:py-1.5 fk:text-sm fk:text-muted-foreground\">Nothing found</li>\n ) : null}\n </ul>\n ) : null}\n </SidebarGroup>\n\n <SidebarGroup>\n <SidebarGroupLabel>Start from</SidebarGroupLabel>\n <SidebarMenu>\n {entities.map((entity) => (\n <SidebarMenuItem key={entity.name}>\n <SidebarMenuButton onClick={() => onStart(entity)} tooltip={getEntityLabel(entity)}>\n <span\n aria-hidden=\"true\"\n className=\"fk:size-2.5 fk:shrink-0 fk:rounded-full\"\n style={{ backgroundColor: colors[entity.name] ?? '#71717a' }}\n />\n <span className=\"fk:truncate\">{getEntityLabel(entity)}</span>\n {totals[entity.plural] !== undefined ? (\n <span className=\"fk:ml-auto fk:text-xs fk:text-muted-foreground\">\n {totals[entity.plural]?.toLocaleString()}\n </span>\n ) : null}\n </SidebarMenuButton>\n </SidebarMenuItem>\n ))}\n </SidebarMenu>\n </SidebarGroup>\n\n {onCanvasEntities.length > 0 ? (\n <SidebarGroup className=\"fk:group-data-[collapsible=icon]:hidden\">\n <SidebarGroupLabel>On canvas</SidebarGroupLabel>\n <ul className=\"fk:flex fk:flex-col\" data-testid=\"graph-legend\">\n {onCanvasEntities.map((name) => {\n const entity = entityByName.get(name);\n const checked = !hiddenEntities.includes(name);\n const id = `graph-legend-${name}`;\n\n return (\n <li className=\"fk:flex fk:h-8 fk:items-center fk:gap-2 fk:px-2 fk:text-sm\" key={name}>\n <span\n aria-hidden=\"true\"\n className=\"fk:size-2.5 fk:shrink-0 fk:rounded-full\"\n style={{ backgroundColor: colors[name] ?? '#71717a', opacity: checked ? 1 : 0.35 }}\n />\n <label className=\"fk:min-w-0 fk:flex-1 fk:cursor-pointer fk:truncate\" htmlFor={id}>\n {entity ? getEntityLabel(entity) : name}\n </label>\n <span className=\"fk:text-xs fk:text-muted-foreground\">{onCanvas[name]?.toLocaleString()}</span>\n <Checkbox\n aria-label={`Show ${entity ? getEntityLabel(entity) : name}`}\n checked={checked}\n id={id}\n onCheckedChange={() => onToggleEntity(name)}\n />\n </li>\n );\n })}\n </ul>\n </SidebarGroup>\n ) : null}\n </SidebarContent>\n <SidebarRail />\n </SidebarPanel>\n );\n}\n","'use client';\n\nimport type { JSX } from 'react';\nimport { EraserIcon, ExpandIcon, EyeOffIcon, LoaderCircleIcon, ScanIcon } from 'lucide-react';\nimport { Button, Separator, Tooltip, TooltipContent, TooltipTrigger } from '../../ui';\n\nexport interface GraphToolbarProps {\n hasSelection: boolean;\n hasNodes: boolean;\n isLoading: boolean;\n onFit: () => void;\n onExpand: () => void;\n onHide: () => void;\n onClear: () => void;\n}\n\nfunction ToolbarButton({\n label,\n icon,\n disabled,\n onClick,\n}: {\n label: string;\n icon: JSX.Element;\n disabled?: boolean;\n onClick: () => void;\n}): JSX.Element {\n return (\n <Tooltip>\n <TooltipTrigger asChild>\n <Button className=\"fk:h-8 fk:gap-1.5 fk:px-2.5\" disabled={disabled} onClick={onClick} size=\"sm\" variant=\"ghost\">\n {icon}\n <span className=\"fk:text-xs\">{label}</span>\n </Button>\n </TooltipTrigger>\n <TooltipContent>{label}</TooltipContent>\n </Tooltip>\n );\n}\n\n/** The floating actions over the canvas. */\nexport function GraphToolbar({\n hasSelection,\n hasNodes,\n isLoading,\n onFit,\n onExpand,\n onHide,\n onClear,\n}: GraphToolbarProps): JSX.Element {\n return (\n <div\n className=\"fk:flex fk:items-center fk:gap-0.5 fk:rounded-lg fk:border fk:bg-background fk:p-1 fk:shadow-xs\"\n data-testid=\"graph-toolbar\"\n >\n <ToolbarButton disabled={!hasNodes} icon={<ScanIcon className=\"fk:size-3.5\" />} label=\"Fit\" onClick={onFit} />\n <Separator className=\"fk:mx-0.5 fk:h-4\" orientation=\"vertical\" />\n <ToolbarButton\n disabled={!hasSelection || isLoading}\n icon={isLoading ? <LoaderCircleIcon className=\"fk:size-3.5 fk:animate-spin\" /> : <ExpandIcon className=\"fk:size-3.5\" />}\n label=\"Expand\"\n onClick={onExpand}\n />\n <ToolbarButton disabled={!hasSelection} icon={<EyeOffIcon className=\"fk:size-3.5\" />} label=\"Hide\" onClick={onHide} />\n <Separator className=\"fk:mx-0.5 fk:h-4\" orientation=\"vertical\" />\n <ToolbarButton disabled={!hasNodes} icon={<EraserIcon className=\"fk:size-3.5\" />} label=\"Clear\" onClick={onClear} />\n </div>\n );\n}\n","'use client';\n\nimport { useCallback, useReducer, useState } from 'react';\nimport type { Dispatch } from 'react';\nimport { gql } from '@apollo/client';\nimport { useApolloClient } from '@apollo/client/react';\nimport { toast } from '../../ui';\nimport type { Attribute, Entity } from '../../core/types';\nimport {\n buildExpandQuery,\n buildRecordsQuery,\n EXPAND_PAGE,\n fetchedFromRecords,\n getEntity,\n graphFromRecords,\n nodeKey,\n type GraphRecord,\n} from './graph';\nimport { EMPTY_SCENE, sceneReducer, type SceneAction, type SceneState } from './scene';\n\n/** Which records to load: given ids (with their first hop when `expand`), or a sample. */\nexport type RecordSelection = { ids: string[]; expand: boolean } | { limit: number };\n\nexport interface SceneApi {\n state: SceneState;\n dispatch: Dispatch<SceneAction>;\n isLoading: boolean;\n /** Loads records, with the first page of each relationship when asked; resolves to their node keys. */\n loadRecords: (entity: Entity, selection: RecordSelection) => Promise<string[]>;\n /** Loads the first page of every relationship of a node. */\n expandAll: (key: string) => Promise<void>;\n /** Loads the next page of one relationship of a node. */\n expandAttribute: (key: string, attribute: Attribute) => Promise<void>;\n}\n\ntype RecordsResult = { [plural: string]: GraphRecord[] };\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : 'The records could not be loaded.';\n}\n\n/**\n * The scene plus the loaders that grow it through the project GraphQL API,\n * so the roles and spaces of the signed-in member apply to every node.\n */\nexport function useScene({ schema, scope }: { schema: Entity[]; scope: string }): SceneApi {\n const client = useApolloClient();\n const [state, dispatch] = useReducer(sceneReducer, EMPTY_SCENE);\n const [pending, setPending] = useState(0);\n\n const loadRecords = useCallback(\n async (entity: Entity, selection: RecordSelection): Promise<string[]> => {\n const ids = 'ids' in selection ? selection.ids : undefined;\n const expand = 'ids' in selection ? selection.expand : false;\n const limit = 'limit' in selection ? selection.limit : ids?.length;\n setPending((count) => count + 1);\n\n try {\n const result = await client.query<RecordsResult>({\n query: gql(buildRecordsQuery({ entity, schema, scope, expand })),\n variables: {\n where: ids ? { _id: { in: ids } } : undefined,\n limit,\n },\n fetchPolicy: 'network-only',\n });\n const records = result.data?.[entity.plural] ?? [];\n dispatch({\n type: 'merge',\n data: graphFromRecords({ records, entity, schema, scope }),\n fetched: fetchedFromRecords(records, entity),\n });\n\n return records.map((record) => nodeKey(entity.name, record._id));\n } catch (error) {\n toast.error(errorMessage(error));\n\n return [];\n } finally {\n setPending((count) => count - 1);\n }\n },\n [client, schema, scope]\n );\n\n const expandAll = useCallback(\n async (key: string): Promise<void> => {\n const node = state.nodes[key];\n const entity = node ? getEntity(schema, node.entity) : undefined;\n\n if (!node || !entity) {\n return;\n }\n\n await loadRecords(entity, { ids: [node.id], expand: true });\n },\n [loadRecords, schema, state.nodes]\n );\n\n const expandAttribute = useCallback(\n async (key: string, attribute: Attribute): Promise<void> => {\n const node = state.nodes[key];\n const entity = node ? getEntity(schema, node.entity) : undefined;\n\n if (!node || !entity) {\n return;\n }\n\n const offset = state.fetched[key]?.[attribute.name] ?? 0;\n setPending((count) => count + 1);\n\n try {\n const result = await client.query<RecordsResult>({\n query: gql(buildExpandQuery({ entity, schema, scope, attribute })),\n variables: { id: node.id, offset, limit: EXPAND_PAGE },\n fetchPolicy: 'network-only',\n });\n const records = result.data?.[entity.plural] ?? [];\n const received = records.reduce((sum, record) => {\n const related = record[attribute.name];\n\n return sum + (Array.isArray(related) ? related.length : 0);\n }, 0);\n dispatch({\n type: 'merge',\n data: graphFromRecords({ records, entity, schema, scope }),\n fetched: { [key]: { [attribute.name]: offset + received } },\n });\n } catch (error) {\n toast.error(errorMessage(error));\n } finally {\n setPending((count) => count - 1);\n }\n },\n [client, schema, scope, state.fetched, state.nodes]\n );\n\n return { state, dispatch, isLoading: pending > 0, loadRecords, expandAll, expandAttribute };\n}\n","'use client';\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { JSX } from 'react';\nimport { useLocation } from 'react-router-dom';\nimport { useAuth } from '../../auth/auth-context';\nimport { useAppContext } from '../../core/app-context';\nimport { useConfig } from '../../core/config/config-context';\nimport { filterEntitiesForSpaces } from '../../core/spaces';\nimport type { Attribute } from '../../core/types';\nimport { useDispatch } from '../../entities/actions-context';\nimport {\n readSidebarCookieState,\n SidebarInset,\n SidebarProvider,\n SidebarTrigger,\n Tooltip,\n TooltipContent,\n TooltipTrigger,\n} from '../../ui';\nimport { useTheme } from '../../ui/theme-context';\nimport { GraphCanvas, type GraphCanvasApi } from './canvas';\nimport { GraphContextMenu, type GraphContextMenuState } from './context-menu';\nimport {\n EXPAND_HOP_MAX_RECORDS,\n getEntity,\n getEntityColors,\n getGraphEntities,\n getRelationshipAttributes,\n parseGraphParams,\n SAMPLE_LIMIT,\n} from './graph';\nimport { GraphInspector } from './inspector';\nimport { countNodesByEntity, neighbourKeys } from './scene';\nimport { GraphSidebar } from './sidebar';\nimport { GraphToolbar } from './toolbar';\nimport { useScene } from './use-scene';\n\n/**\n * The Graph app: explore records as nodes and relationships. The sidebar\n * adds records, the canvas draws them, the inspector details the selection.\n * Other apps open it with `?entity=<name>&ids=<id,id>` to show those records\n * expanded one hop.\n */\nexport function Root(): JSX.Element {\n const { currentProjectId, currentProject, currentProjectSchema } = useConfig();\n const [, auth] = useAuth();\n const { scope } = useAppContext();\n const { resolvedTheme } = useTheme();\n const location = useLocation();\n const dispatchAction = useDispatch();\n const theme = resolvedTheme === 'dark' ? 'dark' : 'light';\n const defaultScope = currentProject?.scopes?.find((item) => item.isDefault)?.name ?? 'default';\n const scopeField = scope || defaultScope;\n // Space-bound entities are hidden from non-members, as in Desk; the API\n // rejects their data either way.\n const userSpaces = auth.user?.spaces;\n const schema = useMemo(() => filterEntitiesForSpaces(currentProjectSchema, userSpaces), [currentProjectSchema, userSpaces]);\n const entities = useMemo(() => getGraphEntities(schema), [schema]);\n const colors = useMemo(() => getEntityColors(schema, theme), [schema, theme]);\n const scene = useScene({ schema, scope: scopeField });\n const { state, dispatch, isLoading, loadRecords, expandAll, expandAttribute } = scene;\n const canvasApi = useRef<GraphCanvasApi | null>(null);\n const [menu, setMenu] = useState<GraphContextMenuState | null>(null);\n const [isLayoutRunning, setIsLayoutRunning] = useState(false);\n const loadedSearchRef = useRef<string | null>(null);\n const onCanvas = useMemo(() => countNodesByEntity(state), [state]);\n const selectedNode = state.selected ? state.nodes[state.selected] : undefined;\n const menuNode = menu ? state.nodes[menu.key] : undefined;\n const menuEntity = menuNode ? getEntity(schema, menuNode.entity) : undefined;\n const nodeCount = Object.keys(state.nodes).length;\n const edgeCount = Object.keys(state.edges).length;\n const defaultOpen = readSidebarCookieState();\n\n const select = useCallback((key: string | null) => dispatch({ type: 'select', key }), [dispatch]);\n\n const openRecord = useCallback(\n (key: string) => {\n const node = state.nodes[key];\n const entity = node ? getEntity(schema, node.entity) : undefined;\n\n if (node && entity) {\n dispatchAction({ type: 'EditEntity', payload: { entityId: node.id, entityNamePlural: entity.plural } });\n }\n },\n [dispatchAction, schema, state.nodes]\n );\n\n const hide = useCallback((key: string) => dispatch({ type: 'remove', keys: [key] }), [dispatch]);\n\n const hideOthers = useCallback(\n (key: string) => dispatch({ type: 'keepOnly', keys: [key, ...neighbourKeys(state, key)] }),\n [dispatch, state]\n );\n\n const togglePin = useCallback((key: string) => dispatch({ type: 'togglePin', key }), [dispatch]);\n\n const pin = useCallback(\n (key: string) => {\n if (!state.pinned[key]) {\n dispatch({ type: 'togglePin', key });\n }\n },\n [dispatch, state.pinned]\n );\n\n const addRecord = useCallback(\n async (entityName: string, id: string) => {\n const entity = getEntity(schema, entityName);\n\n if (!entity) {\n return;\n }\n\n const [key] = await loadRecords(entity, { ids: [id], expand: true });\n\n if (key) {\n select(key);\n }\n },\n [loadRecords, schema, select]\n );\n\n const expandAttributeAndClose = useCallback(\n (key: string, attribute: Attribute) => {\n setMenu(null);\n void expandAttribute(key, attribute);\n },\n [expandAttribute]\n );\n\n // Records another app asked for: `?entity=product&ids=a,b` loads those\n // records, expanded one hop when they are few, `?entity=product` a sample.\n useEffect(() => {\n const params = parseGraphParams(location.search);\n\n // Keyed on the navigation, not the query string: opening the same\n // records again after a Clear must load them again.\n if (!params || loadedSearchRef.current === location.key) {\n return;\n }\n\n const entity = getEntity(schema, params.entity);\n\n if (!entity || schema.length === 0) {\n return;\n }\n\n loadedSearchRef.current = location.key;\n const selection =\n params.ids.length > 0\n ? { ids: params.ids, expand: params.ids.length <= EXPAND_HOP_MAX_RECORDS }\n : { limit: SAMPLE_LIMIT };\n void loadRecords(entity, selection).then((keys) => {\n if (params.ids.length === 1 && keys[0]) {\n select(keys[0]);\n }\n });\n }, [location.key, location.search, schema, loadRecords, select]);\n\n if (!currentProjectId) {\n return (\n <main className=\"fk:flex fk:h-full fk:flex-1 fk:items-center fk:justify-center fk:p-8 fk:text-sm fk:text-muted-foreground\">\n Select a project to explore its graph.\n </main>\n );\n }\n\n return (\n <SidebarProvider className=\"fk:h-full\" defaultOpen={defaultOpen}>\n <GraphSidebar\n colors={colors}\n entities={entities}\n hiddenEntities={state.hiddenEntities}\n onCanvas={onCanvas}\n onHit={(entityName, id) => void addRecord(entityName, id)}\n onStart={(entity) => void loadRecords(entity, { limit: SAMPLE_LIMIT })}\n onToggleEntity={(entityName) => dispatch({ type: 'toggleEntity', entity: entityName })}\n projectId={currentProjectId}\n />\n <SidebarInset className=\"fk:min-w-0\">\n <div className=\"fk:flex fk:h-full fk:min-h-0 fk:min-w-0\" data-testid=\"graph-app\">\n <div className=\"fk:relative fk:min-w-0 fk:flex-1 fk:overflow-hidden fk:bg-background\">\n <div className=\"fk:absolute fk:left-3 fk:top-3 fk:z-10 fk:flex fk:items-center fk:gap-2\">\n <Tooltip>\n <TooltipTrigger asChild>\n <SidebarTrigger className=\"fk:h-8 fk:w-8 fk:rounded-lg fk:hover:bg-transparent fk:dark:hover:bg-transparent\" />\n </TooltipTrigger>\n <TooltipContent>Toggle Sidebar</TooltipContent>\n </Tooltip>\n <GraphToolbar\n hasNodes={nodeCount > 0}\n hasSelection={selectedNode !== undefined}\n isLoading={isLoading}\n onClear={() => dispatch({ type: 'clear' })}\n onExpand={() => {\n if (state.selected) {\n void expandAll(state.selected);\n }\n }}\n onFit={() => canvasApi.current?.fit()}\n onHide={() => {\n if (state.selected) {\n hide(state.selected);\n }\n }}\n />\n </div>\n {nodeCount > 0 ? null : (\n <div className=\"fk:pointer-events-none fk:absolute fk:inset-0 fk:flex fk:items-center fk:justify-center fk:p-8 fk:text-center fk:text-sm fk:text-muted-foreground\">\n {isLoading ? 'Loading records…' : 'Search a record or start from an entity to draw its graph.'}\n </div>\n )}\n <GraphCanvas\n apiRef={canvasApi}\n colors={colors}\n onContextMenu={(key, position) => setMenu({ key, ...position })}\n onExpand={(key) => void expandAll(key)}\n onLayoutChange={setIsLayoutRunning}\n onPin={pin}\n onSelect={select}\n scene={state}\n theme={theme}\n />\n <div\n className=\"fk:absolute fk:bottom-3 fk:left-3 fk:flex fk:max-w-[calc(100%-1.5rem)] fk:items-center fk:gap-2 fk:rounded-lg fk:border fk:bg-background fk:px-2.5 fk:py-1.5 fk:text-xs fk:text-muted-foreground fk:shadow-xs\"\n data-testid=\"graph-status\"\n >\n <span>\n {nodeCount.toLocaleString()} {nodeCount === 1 ? 'node' : 'nodes'} · {edgeCount.toLocaleString()}{' '}\n {edgeCount === 1 ? 'relationship' : 'relationships'}\n </span>\n {isLayoutRunning ? <span>· laying out…</span> : null}\n {state.notice ? <span className=\"fk:truncate fk:text-foreground\">· {state.notice}</span> : null}\n </div>\n <GraphContextMenu\n isPinned={menu ? state.pinned[menu.key] === true : false}\n menu={menu}\n onClose={() => setMenu(null)}\n onExpandAll={(key) => void expandAll(key)}\n onExpandAttribute={expandAttributeAndClose}\n onHide={hide}\n onHideOthers={hideOthers}\n onOpenRecord={openRecord}\n onTogglePin={togglePin}\n relationships={menuEntity ? getRelationshipAttributes(menuEntity) : []}\n />\n </div>\n {selectedNode ? (\n <GraphInspector\n colors={colors}\n isLoading={isLoading}\n node={selectedNode}\n onClose={() => select(null)}\n onExpandAll={(key) => void expandAll(key)}\n onExpandAttribute={(key, attribute) => void expandAttribute(key, attribute)}\n onHide={hide}\n onOpenRecord={openRecord}\n scene={state}\n schema={schema}\n scope={scopeField}\n />\n ) : null}\n </div>\n </SidebarInset>\n </SidebarProvider>\n );\n}\n"]}
|