@mastra/playground-ui 67.0.0 → 68.0.0-alpha.0
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/KnowledgePageGraph.css +11 -0
- package/dist/components/ai/tool-approval.cjs.js +1 -1
- package/dist/components/ai/tool-approval.es.js +1 -1
- package/dist/components/ai/tool-call.cjs.js +2 -2
- package/dist/components/ai/tool-call.es.js +2 -2
- package/dist/domains/chat/activity/model/activity-segments.cjs.js +1 -1
- package/dist/domains/chat/activity/model/activity-segments.es.js +1 -1
- package/dist/domains/chat/activity/model/activity-words.cjs.js +2 -2
- package/dist/domains/chat/activity/model/activity-words.es.js +2 -2
- package/dist/domains/chat/knowledge/knowledge-links.cjs.js +40 -0
- package/dist/domains/chat/knowledge/knowledge-links.cjs.js.map +1 -0
- package/dist/domains/chat/knowledge/knowledge-links.d.ts +1 -0
- package/dist/domains/chat/knowledge/knowledge-links.es.js +38 -0
- package/dist/domains/chat/knowledge/knowledge-links.es.js.map +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js +79 -0
- package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js.map +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge-data.d.ts +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js +77 -0
- package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js.map +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js +124 -0
- package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js.map +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge.d.ts +1 -0
- package/dist/domains/chat/knowledge/pinned-knowledge.es.js +123 -0
- package/dist/domains/chat/knowledge/pinned-knowledge.es.js.map +1 -0
- package/dist/domains/chat/knowledge.cjs.js +12 -0
- package/dist/domains/chat/knowledge.d.ts +1 -0
- package/dist/domains/chat/knowledge.es.js +5 -0
- package/dist/domains/chat/messages/message-row.cjs.js +2 -2
- package/dist/domains/chat/messages/message-row.es.js +2 -2
- package/dist/domains/chat/messages/signal-badge.cjs.js +7 -0
- package/dist/domains/chat/messages/signal-badge.cjs.js.map +1 -1
- package/dist/domains/chat/messages/signal-badge.es.js +7 -0
- package/dist/domains/chat/messages/signal-badge.es.js.map +1 -1
- package/dist/domains/chat/tools/badges/agent-badge-wrapper.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/agent-badge-wrapper.es.js +1 -1
- package/dist/domains/chat/tools/badges/agent-badge.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/agent-badge.es.js +1 -1
- package/dist/domains/chat/tools/badges/file-tree-badge.cjs.js +2 -2
- package/dist/domains/chat/tools/badges/file-tree-badge.es.js +2 -2
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js +273 -0
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js.map +1 -0
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.d.ts +1 -0
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js +270 -0
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js.map +1 -0
- package/dist/domains/chat/tools/badges/observation-marker-badge.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/observation-marker-badge.es.js +1 -1
- package/dist/domains/chat/tools/badges/sandbox-execution-badge.cjs.js +2 -2
- package/dist/domains/chat/tools/badges/sandbox-execution-badge.es.js +2 -2
- package/dist/domains/chat/tools/badges/tool-approval-badge.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/tool-approval-badge.es.js +1 -1
- package/dist/domains/chat/tools/badges/tool-badge.cjs.js +3 -3
- package/dist/domains/chat/tools/badges/tool-badge.es.js +3 -3
- package/dist/domains/chat/tools/badges/workflow-badge.cjs.js +2 -2
- package/dist/domains/chat/tools/badges/workflow-badge.es.js +2 -2
- package/dist/domains/chat/tools/tool-card-kind.cjs.js +4 -2
- package/dist/domains/chat/tools/tool-card-kind.cjs.js.map +1 -1
- package/dist/domains/chat/tools/tool-card-kind.es.js +4 -2
- package/dist/domains/chat/tools/tool-card-kind.es.js.map +1 -1
- package/dist/domains/chat/tools/tool-card.cjs.js +1 -1
- package/dist/domains/chat/tools/tool-card.es.js +1 -1
- package/dist/domains/chat/tools/tool-groups.cjs.js +3 -2
- package/dist/domains/chat/tools/tool-groups.cjs.js.map +1 -1
- package/dist/domains/chat/tools/tool-groups.es.js +3 -2
- package/dist/domains/chat/tools/tool-groups.es.js.map +1 -1
- package/dist/domains/chat.cjs.js +11 -0
- package/dist/domains/chat.es.js +5 -1
- package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js +438 -0
- package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageDetail.d.ts +1 -0
- package/dist/domains/knowledge/components/KnowledgePageDetail.es.js +436 -0
- package/dist/domains/knowledge/components/KnowledgePageDetail.es.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js +521 -0
- package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageExplorer.d.ts +1 -0
- package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js +520 -0
- package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js +626 -0
- package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageGraph.d.ts +1 -0
- package/dist/domains/knowledge/components/KnowledgePageGraph.es.js +625 -0
- package/dist/domains/knowledge/components/KnowledgePageGraph.es.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js +170 -0
- package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageTree.d.ts +1 -0
- package/dist/domains/knowledge/components/KnowledgePageTree.es.js +168 -0
- package/dist/domains/knowledge/components/KnowledgePageTree.es.js.map +1 -0
- package/dist/domains/knowledge/hooks/useInteractionIdle.cjs.js +37 -0
- package/dist/domains/knowledge/hooks/useInteractionIdle.cjs.js.map +1 -0
- package/dist/domains/knowledge/hooks/useInteractionIdle.d.ts +1 -0
- package/dist/domains/knowledge/hooks/useInteractionIdle.es.js +35 -0
- package/dist/domains/knowledge/hooks/useInteractionIdle.es.js.map +1 -0
- package/dist/domains/knowledge/lib/layout.cjs.js +93 -0
- package/dist/domains/knowledge/lib/layout.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/layout.d.ts +1 -0
- package/dist/domains/knowledge/lib/layout.es.js +92 -0
- package/dist/domains/knowledge/lib/layout.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageGraph.cjs.js +135 -0
- package/dist/domains/knowledge/lib/pageGraph.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/pageGraph.d.ts +1 -0
- package/dist/domains/knowledge/lib/pageGraph.es.js +128 -0
- package/dist/domains/knowledge/lib/pageGraph.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageLayout.cjs.js +49 -0
- package/dist/domains/knowledge/lib/pageLayout.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/pageLayout.d.ts +1 -0
- package/dist/domains/knowledge/lib/pageLayout.es.js +48 -0
- package/dist/domains/knowledge/lib/pageLayout.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageTree.cjs.js +98 -0
- package/dist/domains/knowledge/lib/pageTree.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/pageTree.d.ts +1 -0
- package/dist/domains/knowledge/lib/pageTree.es.js +94 -0
- package/dist/domains/knowledge/lib/pageTree.es.js.map +1 -0
- package/dist/domains/knowledge/lib/popupPlacement.cjs.js +22 -0
- package/dist/domains/knowledge/lib/popupPlacement.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/popupPlacement.d.ts +1 -0
- package/dist/domains/knowledge/lib/popupPlacement.es.js +21 -0
- package/dist/domains/knowledge/lib/popupPlacement.es.js.map +1 -0
- package/dist/domains/knowledge/lib/recordText.cjs.js +26 -0
- package/dist/domains/knowledge/lib/recordText.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/recordText.d.ts +1 -0
- package/dist/domains/knowledge/lib/recordText.es.js +25 -0
- package/dist/domains/knowledge/lib/recordText.es.js.map +1 -0
- package/dist/domains/knowledge/pageTypes.cjs.js +0 -0
- package/dist/domains/knowledge/pageTypes.d.ts +1 -0
- package/dist/domains/knowledge/pageTypes.es.js +0 -0
- package/dist/domains/logs/components/logs-saved-views.cjs.js +1 -1
- package/dist/domains/logs/components/logs-saved-views.es.js +1 -1
- package/dist/domains/observability/saved-views/observability-saved-views.cjs.js +1 -1
- package/dist/domains/observability/saved-views/observability-saved-views.es.js +1 -1
- package/dist/domains/observability/saved-views/saved-views-provider.cjs.js +3 -2
- package/dist/domains/observability/saved-views/saved-views-provider.cjs.js.map +1 -1
- package/dist/domains/observability/saved-views/saved-views-provider.es.js +3 -2
- package/dist/domains/observability/saved-views/saved-views-provider.es.js.map +1 -1
- package/dist/domains/observability/saved-views/saved-views-source.cjs.js.map +1 -1
- package/dist/domains/observability/saved-views/saved-views-source.es.js.map +1 -1
- package/dist/domains/observability/saved-views/use-hosted-saved-views.cjs.js +3 -2
- package/dist/domains/observability/saved-views/use-hosted-saved-views.cjs.js.map +1 -1
- package/dist/domains/observability/saved-views/use-hosted-saved-views.es.js +3 -2
- package/dist/domains/observability/saved-views/use-hosted-saved-views.es.js.map +1 -1
- package/dist/domains/observability/saved-views.cjs.js +1 -1
- package/dist/domains/observability/saved-views.es.js +1 -1
- package/dist/domains/observability.cjs.js +1 -1
- package/dist/domains/observability.es.js +1 -1
- package/dist/domains/skills/skill-simple-form.cjs.js +2 -2
- package/dist/domains/skills/skill-simple-form.cjs.js.map +1 -1
- package/dist/domains/skills/skill-simple-form.es.js +2 -2
- package/dist/domains/skills/skill-simple-form.es.js.map +1 -1
- package/dist/domains/spans/components/spans-explorer-body.cjs.js +1 -1
- package/dist/domains/spans/components/spans-explorer-body.es.js +1 -1
- package/dist/domains/threads/components/threads-explorer-body.cjs.js +1 -1
- package/dist/domains/threads/components/threads-explorer-body.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-error-renderer.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-error-renderer.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-input-renderers.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-input-renderers.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-output-renderers.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-output-renderers.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-messages.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-messages.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-primitives.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-primitives.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-processor.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-processor.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-tool.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-payload-tool.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-processor-mutations.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-processor-mutations.es.js +1 -1
- package/dist/domains/traces/components/span-payload/span-tools-section.cjs.js +1 -1
- package/dist/domains/traces/components/span-payload/span-tools-section.es.js +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.cjs.js +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-saved-views.es.js +1 -1
- package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js +2 -1
- package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js.map +1 -1
- package/dist/domains/workflows/workflow/use-workflow-trigger.es.js +2 -1
- package/dist/domains/workflows/workflow/use-workflow-trigger.es.js.map +1 -1
- package/dist/lib/form/dynamic-form.cjs.js +2 -2
- package/dist/lib/form/dynamic-form.cjs.js.map +1 -1
- package/dist/lib/form/dynamic-form.es.js +2 -2
- package/dist/lib/form/dynamic-form.es.js.map +1 -1
- package/dist/lib/form/json-draft.cjs.js +1 -1
- package/dist/lib/form/json-draft.es.js +1 -1
- package/dist/lib/form/zod-provider/compat.cjs.js +8 -0
- package/dist/lib/form/zod-provider/compat.cjs.js.map +1 -1
- package/dist/lib/form/zod-provider/compat.es.js +8 -1
- package/dist/lib/form/zod-provider/compat.es.js.map +1 -1
- package/dist/lib/form/zod-provider.cjs.js +1 -1
- package/dist/lib/form/zod-provider.es.js +1 -1
- package/dist/{observability-saved-views-CwCii7hh.cjs → observability-saved-views-BNU3GkK6.cjs} +8 -6
- package/dist/observability-saved-views-BNU3GkK6.cjs.map +1 -0
- package/dist/{observability-saved-views-Bo5kLN20.js → observability-saved-views-Zlz74syw.js} +8 -6
- package/dist/observability-saved-views-Zlz74syw.js.map +1 -0
- package/dist/{span-payload-primitives-Dyhbqaa7.js → span-payload-primitives-ChvD2RrN.js} +2 -2
- package/dist/{span-payload-primitives-Dyhbqaa7.js.map → span-payload-primitives-ChvD2RrN.js.map} +1 -1
- package/dist/{span-payload-primitives-B10Xxmx7.cjs → span-payload-primitives-w1vtAXAw.cjs} +2 -2
- package/dist/{span-payload-primitives-B10Xxmx7.cjs.map → span-payload-primitives-w1vtAXAw.cjs.map} +1 -1
- package/dist/src/domains/chat/index.d.ts +1 -0
- package/dist/src/domains/chat/knowledge/index.d.ts +5 -0
- package/dist/src/domains/chat/knowledge/knowledge-links.d.ts +21 -0
- package/dist/src/domains/chat/knowledge/pinned-knowledge-data.d.ts +22 -0
- package/dist/src/domains/chat/knowledge/pinned-knowledge.d.ts +9 -0
- package/dist/src/domains/chat/tools/badges/knowledge-tool-badge.d.ts +19 -0
- package/dist/src/domains/chat/tools/tool-card-kind.d.ts +2 -2
- package/dist/src/domains/knowledge/components/KnowledgePageDetail.d.ts +42 -0
- package/dist/src/domains/knowledge/components/KnowledgePageExplorer.d.ts +80 -0
- package/dist/src/domains/knowledge/components/KnowledgePageGraph.d.ts +35 -0
- package/dist/src/domains/knowledge/components/KnowledgePageTree.d.ts +27 -0
- package/dist/src/domains/knowledge/hooks/useInteractionIdle.d.ts +12 -0
- package/dist/src/domains/knowledge/lib/layout.d.ts +35 -0
- package/dist/src/domains/knowledge/lib/pageGraph.d.ts +45 -0
- package/dist/src/domains/knowledge/lib/pageLayout.d.ts +24 -0
- package/dist/src/domains/knowledge/lib/pageTree.d.ts +28 -0
- package/dist/src/domains/knowledge/lib/popupPlacement.d.ts +12 -0
- package/dist/src/domains/knowledge/lib/recordText.d.ts +9 -0
- package/dist/src/domains/knowledge/pageTypes.d.ts +96 -0
- package/dist/src/domains/observability/saved-views/saved-views-provider.d.ts +6 -1
- package/dist/src/domains/observability/saved-views/saved-views-source.d.ts +1 -0
- package/dist/src/domains/observability/saved-views/use-hosted-saved-views.d.ts +1 -1
- package/dist/src/domains/skills/skill-simple-form.d.ts +3 -1
- package/dist/src/ds/components/SavedViews/saved-view-picker.d.ts +3 -1
- package/dist/src/ds/components/ai/tool-call/tool-phrases.d.ts +30 -0
- package/dist/src/lib/form/zod-provider/compat.d.ts +5 -0
- package/dist/style.css +63 -1
- package/dist/{tool-approval-FeuyUUcL.js → tool-approval-DHeCkWHT.js} +3 -3
- package/dist/{tool-approval-FeuyUUcL.js.map → tool-approval-DHeCkWHT.js.map} +1 -1
- package/dist/{tool-approval-BfjoSNOC.cjs → tool-approval-Dfi0uAKU.cjs} +3 -3
- package/dist/{tool-approval-BfjoSNOC.cjs.map → tool-approval-Dfi0uAKU.cjs.map} +1 -1
- package/dist/{tool-call-CvilN9ti.cjs → tool-call-BCsDhIhs.cjs} +32 -2
- package/dist/{tool-call-CvilN9ti.cjs.map → tool-call-BCsDhIhs.cjs.map} +1 -1
- package/dist/{tool-call-BxYXs9w0.js → tool-call-CILZa3tn.js} +32 -2
- package/dist/{tool-call-BxYXs9w0.js.map → tool-call-CILZa3tn.js.map} +1 -1
- package/dist/{tool-card-ELW898uw.js → tool-card-C3sDFUWc.js} +18 -4
- package/dist/tool-card-C3sDFUWc.js.map +1 -0
- package/dist/{tool-card-B7O8AsRl.cjs → tool-card-CJ7Kxi-U.cjs} +18 -4
- package/dist/tool-card-CJ7Kxi-U.cjs.map +1 -0
- package/dist/{tool-presentation-BLErsb7c.cjs → tool-presentation-CQlDEwgS.cjs} +26 -1
- package/dist/tool-presentation-CQlDEwgS.cjs.map +1 -0
- package/dist/{tool-presentation-BSZYIWx2.js → tool-presentation-DvCsb_kz.js} +26 -1
- package/dist/tool-presentation-DvCsb_kz.js.map +1 -0
- package/package.json +11 -9
- package/dist/observability-saved-views-Bo5kLN20.js.map +0 -1
- package/dist/observability-saved-views-CwCii7hh.cjs.map +0 -1
- package/dist/tool-card-B7O8AsRl.cjs.map +0 -1
- package/dist/tool-card-ELW898uw.js.map +0 -1
- package/dist/tool-presentation-BLErsb7c.cjs.map +0 -1
- package/dist/tool-presentation-BSZYIWx2.js.map +0 -1
|
@@ -0,0 +1,520 @@
|
|
|
1
|
+
import { t as Txt } from "../../../Txt-BM6TVV_c.js";
|
|
2
|
+
import { n as EmptyState } from "../../../EmptyState-P-Gy898T.js";
|
|
3
|
+
import { useIsMobile } from "../../../hooks/use-is-mobile.es.js";
|
|
4
|
+
import { KnowledgeNoteItem, KnowledgePageDetail } from "./KnowledgePageDetail.es.js";
|
|
5
|
+
import { mentionPopupPlacement } from "../lib/popupPlacement.es.js";
|
|
6
|
+
import { KnowledgePageGraph } from "./KnowledgePageGraph.es.js";
|
|
7
|
+
import { KnowledgePageTree } from "./KnowledgePageTree.es.js";
|
|
8
|
+
import { useCallback, useEffect, useMemo, useState } from "react";
|
|
9
|
+
import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
|
|
10
|
+
import { X } from "lucide-react";
|
|
11
|
+
// src/domains/knowledge/components/KnowledgePageExplorer.tsx
|
|
12
|
+
var MIN_SEARCH_LENGTH = 2;
|
|
13
|
+
var noTreeLevels = () => [];
|
|
14
|
+
var noActivity = () => ({
|
|
15
|
+
isPending: false,
|
|
16
|
+
isError: false,
|
|
17
|
+
error: null
|
|
18
|
+
});
|
|
19
|
+
function isNotFound(error) {
|
|
20
|
+
return !!error && typeof error === "object" && "status" in error && error.status === 404;
|
|
21
|
+
}
|
|
22
|
+
function withPages(base, pages) {
|
|
23
|
+
if (pages.length === 0) return base;
|
|
24
|
+
const merged = new Map(base);
|
|
25
|
+
for (const page of pages) merged.set(page.id, page);
|
|
26
|
+
return merged;
|
|
27
|
+
}
|
|
28
|
+
/** `pages` narrowed to `scopeId` and everything below it, following parent links among the given pages. */
|
|
29
|
+
function withinScope(pages, scopeId) {
|
|
30
|
+
if (!scopeId) return pages;
|
|
31
|
+
const byId = new Map(pages.map((page) => [page.id, page]));
|
|
32
|
+
const inside = /* @__PURE__ */ new Map([[scopeId, true]]);
|
|
33
|
+
const isInside = (page) => {
|
|
34
|
+
const known = inside.get(page.id);
|
|
35
|
+
if (known !== void 0) return known;
|
|
36
|
+
const parent = page.parentId ? byId.get(page.parentId) : void 0;
|
|
37
|
+
inside.set(page.id, false);
|
|
38
|
+
const result = !!parent && parent.id !== page.id && isInside(parent);
|
|
39
|
+
inside.set(page.id, result);
|
|
40
|
+
return result;
|
|
41
|
+
};
|
|
42
|
+
return pages.filter(isInside);
|
|
43
|
+
}
|
|
44
|
+
function MoreButton({ onClick, label = "Load more" }) {
|
|
45
|
+
return /* @__PURE__ */ jsx("button", {
|
|
46
|
+
type: "button",
|
|
47
|
+
className: "self-start text-caption text-muted-foreground hover:text-foreground",
|
|
48
|
+
onClick,
|
|
49
|
+
children: label
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/** The next page of a page's notes, then a button for the one after. */
|
|
53
|
+
function MoreNotes({ source, pageId, cursor, pagesById, onPageClick }) {
|
|
54
|
+
const chunk = source.usePage(pageId, cursor);
|
|
55
|
+
const [showNext, setShowNext] = useState(false);
|
|
56
|
+
const known = useMemo(() => withPages(pagesById, chunk.data?.related ?? []), [chunk.data, pagesById]);
|
|
57
|
+
if (chunk.isPending) return /* @__PURE__ */ jsx("p", {
|
|
58
|
+
className: "text-caption text-muted-foreground",
|
|
59
|
+
children: "Loading notes…"
|
|
60
|
+
});
|
|
61
|
+
if (!chunk.data) return null;
|
|
62
|
+
const next = chunk.data.notesNextCursor;
|
|
63
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("ul", {
|
|
64
|
+
className: "flex flex-col gap-3",
|
|
65
|
+
children: chunk.data.notes.map((note) => /* @__PURE__ */ jsx(KnowledgeNoteItem, {
|
|
66
|
+
note,
|
|
67
|
+
pagesById: known,
|
|
68
|
+
onPageClick
|
|
69
|
+
}, note.id))
|
|
70
|
+
}), next ? showNext ? /* @__PURE__ */ jsx(MoreNotes, {
|
|
71
|
+
source,
|
|
72
|
+
pageId,
|
|
73
|
+
cursor: next,
|
|
74
|
+
pagesById,
|
|
75
|
+
onPageClick
|
|
76
|
+
}) : /* @__PURE__ */ jsx(MoreButton, {
|
|
77
|
+
label: "Load more notes",
|
|
78
|
+
onClick: () => setShowNext(true)
|
|
79
|
+
}) : null] });
|
|
80
|
+
}
|
|
81
|
+
/** A page's children, a page at a time. */
|
|
82
|
+
function ChildPages({ useTreeLevels, parentId, onPageClick }) {
|
|
83
|
+
const [cursors, setCursors] = useState([]);
|
|
84
|
+
const levels = useTreeLevels(useMemo(() => [{ parentId }, ...cursors.map((cursor) => ({
|
|
85
|
+
parentId,
|
|
86
|
+
cursor
|
|
87
|
+
}))], [parentId, cursors]));
|
|
88
|
+
const pages = levels.flatMap((level) => level.data?.pages ?? []);
|
|
89
|
+
const last = levels[levels.length - 1];
|
|
90
|
+
if (levels[0]?.isPending) return /* @__PURE__ */ jsx("p", {
|
|
91
|
+
className: "text-caption text-muted-foreground",
|
|
92
|
+
children: "Loading pages…"
|
|
93
|
+
});
|
|
94
|
+
if (pages.length === 0) return /* @__PURE__ */ jsx("p", {
|
|
95
|
+
className: "text-body text-muted-foreground",
|
|
96
|
+
"data-testid": "knowledge-no-child-pages",
|
|
97
|
+
children: "No pages under this one."
|
|
98
|
+
});
|
|
99
|
+
const next = last?.data?.nextCursor;
|
|
100
|
+
return /* @__PURE__ */ jsxs(Fragment$1, { children: [/* @__PURE__ */ jsx("ul", {
|
|
101
|
+
className: "flex flex-col gap-1",
|
|
102
|
+
children: pages.map((child) => /* @__PURE__ */ jsxs("li", {
|
|
103
|
+
className: "flex flex-col",
|
|
104
|
+
children: [/* @__PURE__ */ jsx("button", {
|
|
105
|
+
type: "button",
|
|
106
|
+
className: "text-left text-body font-medium text-info-indicator hover:underline",
|
|
107
|
+
onClick: () => onPageClick(child),
|
|
108
|
+
children: child.name
|
|
109
|
+
}), child.description ? /* @__PURE__ */ jsx("span", {
|
|
110
|
+
className: "truncate text-caption text-muted-foreground",
|
|
111
|
+
children: child.description
|
|
112
|
+
}) : null]
|
|
113
|
+
}, child.id))
|
|
114
|
+
}), next ? /* @__PURE__ */ jsx(MoreButton, { onClick: () => setCursors((current) => [...current, next]) }) : null] });
|
|
115
|
+
}
|
|
116
|
+
/** What a clicked mention line stands for: the notes on one page that mention the other. */
|
|
117
|
+
function MentionPopup({ source, mention, pagesById, onOpen, onClose }) {
|
|
118
|
+
const detail = source.usePage(mention.source.id);
|
|
119
|
+
const notes = (detail.data?.notes ?? []).filter((note) => note.mentions.includes(mention.target.id));
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
const onKey = (event) => {
|
|
122
|
+
if (event.key === "Escape") onClose();
|
|
123
|
+
};
|
|
124
|
+
window.addEventListener("keydown", onKey);
|
|
125
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
126
|
+
}, [onClose]);
|
|
127
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
128
|
+
role: "dialog",
|
|
129
|
+
"aria-label": `${mention.source.name} mentions ${mention.target.name}`,
|
|
130
|
+
"data-testid": "knowledge-mention-popup",
|
|
131
|
+
className: "absolute z-20 flex w-80 max-w-[calc(100%-1rem)] flex-col gap-2 overflow-hidden rounded-lg border border-border bg-card p-3 shadow-overlay",
|
|
132
|
+
style: mentionPopupPlacement(mention),
|
|
133
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
134
|
+
className: "flex items-start gap-2",
|
|
135
|
+
children: [/* @__PURE__ */ jsxs(Txt, {
|
|
136
|
+
as: "h3",
|
|
137
|
+
variant: "card-title",
|
|
138
|
+
className: "min-w-0 flex-1",
|
|
139
|
+
children: [
|
|
140
|
+
/* @__PURE__ */ jsx("button", {
|
|
141
|
+
type: "button",
|
|
142
|
+
className: "hover:underline",
|
|
143
|
+
onClick: () => onOpen(mention.source.id),
|
|
144
|
+
children: mention.source.name
|
|
145
|
+
}),
|
|
146
|
+
/* @__PURE__ */ jsxs(Txt, {
|
|
147
|
+
as: "span",
|
|
148
|
+
variant: "card-title",
|
|
149
|
+
tone: "muted",
|
|
150
|
+
children: [
|
|
151
|
+
" ",
|
|
152
|
+
"mentions",
|
|
153
|
+
" "
|
|
154
|
+
]
|
|
155
|
+
}),
|
|
156
|
+
/* @__PURE__ */ jsx("button", {
|
|
157
|
+
type: "button",
|
|
158
|
+
className: "hover:underline",
|
|
159
|
+
onClick: () => onOpen(mention.target.id),
|
|
160
|
+
children: mention.target.name
|
|
161
|
+
})
|
|
162
|
+
]
|
|
163
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
164
|
+
type: "button",
|
|
165
|
+
"aria-label": "Close",
|
|
166
|
+
className: "rounded p-0.5 text-muted-foreground hover:bg-fill hover:text-foreground",
|
|
167
|
+
onClick: onClose,
|
|
168
|
+
children: /* @__PURE__ */ jsx(X, {
|
|
169
|
+
size: 14,
|
|
170
|
+
"aria-hidden": true
|
|
171
|
+
})
|
|
172
|
+
})]
|
|
173
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
174
|
+
className: "min-h-0 overflow-y-auto",
|
|
175
|
+
children: detail.isPending ? /* @__PURE__ */ jsx(Txt, {
|
|
176
|
+
variant: "caption",
|
|
177
|
+
tone: "muted",
|
|
178
|
+
children: "Loading notes…"
|
|
179
|
+
}) : notes.length === 0 ? /* @__PURE__ */ jsxs(Txt, {
|
|
180
|
+
variant: "caption",
|
|
181
|
+
tone: "muted",
|
|
182
|
+
children: [
|
|
183
|
+
"The notes that make this mention aren't in the first page of notes. Open ",
|
|
184
|
+
mention.source.name,
|
|
185
|
+
" to read them all."
|
|
186
|
+
]
|
|
187
|
+
}) : /* @__PURE__ */ jsx("ul", {
|
|
188
|
+
className: "flex flex-col gap-2",
|
|
189
|
+
children: notes.map((note) => /* @__PURE__ */ jsx(KnowledgeNoteItem, {
|
|
190
|
+
note,
|
|
191
|
+
pagesById: withPages(pagesById, detail.data?.related ?? []),
|
|
192
|
+
onPageClick: (page) => onOpen(page.id),
|
|
193
|
+
compact: true
|
|
194
|
+
}, note.id))
|
|
195
|
+
})
|
|
196
|
+
})]
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
function SelectedPage({ source, pageId, pagesById, onSelect, highlightMentionOf }) {
|
|
200
|
+
const detail = source.usePage(pageId);
|
|
201
|
+
const activity = (source.useActivity ?? noActivity)(pageId);
|
|
202
|
+
const [moreNotes, setMoreNotes] = useState(null);
|
|
203
|
+
const known = useMemo(() => detail.data ? withPages(pagesById, [...detail.data.ancestors, ...detail.data.related]) : pagesById, [detail.data, pagesById]);
|
|
204
|
+
if (detail.isPending) return /* @__PURE__ */ jsx("p", {
|
|
205
|
+
className: "text-ui-md p-4 text-muted-foreground",
|
|
206
|
+
children: "Loading page…"
|
|
207
|
+
});
|
|
208
|
+
if (detail.isError || !detail.data) {
|
|
209
|
+
const notFound = isNotFound(detail.error);
|
|
210
|
+
return /* @__PURE__ */ jsx(EmptyState, {
|
|
211
|
+
tone: "error",
|
|
212
|
+
variant: "fill",
|
|
213
|
+
titleSlot: notFound ? "Page not found" : "Failed to load the page",
|
|
214
|
+
descriptionSlot: notFound ? "It may have been deleted or merged." : detail.error?.message ?? ""
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
const onPageClick = (page) => onSelect(page.id);
|
|
218
|
+
const next = detail.data.notesNextCursor;
|
|
219
|
+
return /* @__PURE__ */ jsx(KnowledgePageDetail, {
|
|
220
|
+
page: detail.data.page,
|
|
221
|
+
notes: detail.data.notes,
|
|
222
|
+
pin: detail.data.pin ?? void 0,
|
|
223
|
+
pagesById: known,
|
|
224
|
+
onPageClick,
|
|
225
|
+
highlightMentionOf,
|
|
226
|
+
ancestors: detail.data.ancestors,
|
|
227
|
+
mentionedBy: detail.data.mentionedBy,
|
|
228
|
+
activity: activity.data?.events,
|
|
229
|
+
childPages: source.useTreeLevels ? /* @__PURE__ */ jsx(ChildPages, {
|
|
230
|
+
useTreeLevels: source.useTreeLevels,
|
|
231
|
+
parentId: pageId,
|
|
232
|
+
onPageClick
|
|
233
|
+
}, pageId) : void 0,
|
|
234
|
+
notesMore: next ? moreNotes?.pageId === pageId ? /* @__PURE__ */ jsx(MoreNotes, {
|
|
235
|
+
source,
|
|
236
|
+
pageId,
|
|
237
|
+
cursor: next,
|
|
238
|
+
pagesById: known,
|
|
239
|
+
onPageClick
|
|
240
|
+
}) : /* @__PURE__ */ jsx(MoreButton, {
|
|
241
|
+
label: "Load more notes",
|
|
242
|
+
onClick: () => setMoreNotes({ pageId })
|
|
243
|
+
}) : void 0
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
function SearchBox({ source, onSelect }) {
|
|
247
|
+
const [query, setQuery] = useState("");
|
|
248
|
+
const search = source.useSearch(query);
|
|
249
|
+
const results = query.trim().length >= MIN_SEARCH_LENGTH ? search.data?.results ?? [] : [];
|
|
250
|
+
const seen = /* @__PURE__ */ new Set();
|
|
251
|
+
const pages = results.map((hit) => hit.page).filter((page) => seen.has(page.id) ? false : (seen.add(page.id), true)).slice(0, 10);
|
|
252
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
253
|
+
className: "relative min-w-60 flex-1",
|
|
254
|
+
children: [/* @__PURE__ */ jsx("input", {
|
|
255
|
+
"aria-label": "Search knowledge",
|
|
256
|
+
placeholder: "Search pages and notes",
|
|
257
|
+
className: "text-ui-md h-8 w-full rounded border border-border bg-card px-2",
|
|
258
|
+
value: query,
|
|
259
|
+
onChange: (event) => setQuery(event.target.value)
|
|
260
|
+
}), pages.length > 0 ? /* @__PURE__ */ jsx("ul", {
|
|
261
|
+
role: "listbox",
|
|
262
|
+
"aria-label": "Search results",
|
|
263
|
+
className: "absolute z-20 mt-1 max-h-72 w-full overflow-auto rounded border border-border bg-card shadow-raised",
|
|
264
|
+
children: pages.map((page) => /* @__PURE__ */ jsx("li", {
|
|
265
|
+
role: "option",
|
|
266
|
+
"aria-selected": false,
|
|
267
|
+
children: /* @__PURE__ */ jsx("button", {
|
|
268
|
+
type: "button",
|
|
269
|
+
className: "text-ui-md w-full px-2 py-1.5 text-left hover:bg-muted",
|
|
270
|
+
onClick: () => {
|
|
271
|
+
onSelect(page.id);
|
|
272
|
+
setQuery("");
|
|
273
|
+
},
|
|
274
|
+
children: page.name
|
|
275
|
+
})
|
|
276
|
+
}, page.id))
|
|
277
|
+
}) : null]
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* The tree loaded a level at a time through `useTreeLevels`: the root scopes, then each level as it is
|
|
282
|
+
* opened, plus the path to the selected page. Unloaded pages keep a chevron until opened.
|
|
283
|
+
*/
|
|
284
|
+
function useLazyTree(source, graph, selected) {
|
|
285
|
+
const [expanded, setExpanded] = useState(() => /* @__PURE__ */ new Set());
|
|
286
|
+
const [more, setMore] = useState(() => /* @__PURE__ */ new Map());
|
|
287
|
+
const requests = useMemo(() => {
|
|
288
|
+
const list = [{ parentId: null }];
|
|
289
|
+
for (const id of expanded) {
|
|
290
|
+
list.push({ parentId: id });
|
|
291
|
+
for (const cursor of more.get(id) ?? []) list.push({
|
|
292
|
+
parentId: id,
|
|
293
|
+
cursor
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
return list;
|
|
297
|
+
}, [expanded, more]);
|
|
298
|
+
const levels = (source.useTreeLevels ?? noTreeLevels)(requests);
|
|
299
|
+
const { pages, loaded, nextCursor } = useMemo(() => {
|
|
300
|
+
const byId = /* @__PURE__ */ new Map();
|
|
301
|
+
const loadedIds = /* @__PURE__ */ new Set();
|
|
302
|
+
const next = /* @__PURE__ */ new Map();
|
|
303
|
+
levels.forEach((level, index) => {
|
|
304
|
+
const request = requests[index];
|
|
305
|
+
if (!request || !level.data) return;
|
|
306
|
+
const key = request.parentId ?? "";
|
|
307
|
+
loadedIds.add(key);
|
|
308
|
+
for (const page of level.data.pages) byId.set(page.id, page);
|
|
309
|
+
if (level.data.nextCursor) next.set(key, level.data.nextCursor);
|
|
310
|
+
else next.delete(key);
|
|
311
|
+
});
|
|
312
|
+
for (const page of [...selected?.ancestors ?? [], ...selected ? [selected.page] : []]) if (!byId.has(page.id)) byId.set(page.id, page);
|
|
313
|
+
return {
|
|
314
|
+
pages: [...byId.values()],
|
|
315
|
+
loaded: loadedIds,
|
|
316
|
+
nextCursor: next
|
|
317
|
+
};
|
|
318
|
+
}, [
|
|
319
|
+
levels,
|
|
320
|
+
requests,
|
|
321
|
+
selected
|
|
322
|
+
]);
|
|
323
|
+
const graphParents = useMemo(() => graph.truncated ? null : new Set(graph.pages.map((page) => page.parentId).filter((id) => id !== null)), [graph]);
|
|
324
|
+
return {
|
|
325
|
+
pages,
|
|
326
|
+
mayHaveChildren: useCallback((page) => !loaded.has(page.id) && (graphParents ? graphParents.has(page.id) : true), [loaded, graphParents]),
|
|
327
|
+
loadMore: useMemo(() => {
|
|
328
|
+
const map = /* @__PURE__ */ new Map();
|
|
329
|
+
for (const [parentId, cursor] of nextCursor) map.set(parentId, () => setMore((current) => new Map(current).set(parentId, [...current.get(parentId) ?? [], cursor])));
|
|
330
|
+
return map;
|
|
331
|
+
}, [nextCursor]),
|
|
332
|
+
onExpandedChange: useCallback((ids) => setExpanded(new Set(ids)), []),
|
|
333
|
+
rootsPending: levels[0]?.isPending ?? false
|
|
334
|
+
};
|
|
335
|
+
}
|
|
336
|
+
/**
|
|
337
|
+
* Search, the page tree, and either the page graph or the selected page, kept in sync on one selection.
|
|
338
|
+
* Wide screens show the tree beside the graph or the page; below `lg` one toggle picks tree, graph or page.
|
|
339
|
+
* A first click on a page in the graph selects it; clicking it again opens it as a page. A search result
|
|
340
|
+
* opens it as a page straight away. Selecting in the tree keeps the current view, so the graph frames the
|
|
341
|
+
* page instead.
|
|
342
|
+
*/
|
|
343
|
+
function KnowledgePageExplorer({ graph, source, selectedPageId, onSelect, view, onViewChange }) {
|
|
344
|
+
const pagesById = useMemo(() => new Map(graph.pages.map((page) => [page.id, page])), [graph.pages]);
|
|
345
|
+
const [focusScopeId, setFocusScopeId] = useState(null);
|
|
346
|
+
const mentionEdges = useMemo(() => graph.edges.filter((edge) => edge.kind === "mention"), [graph.edges]);
|
|
347
|
+
const [mention, setMention] = useState(null);
|
|
348
|
+
const [marked, setMarked] = useState(null);
|
|
349
|
+
const closeMention = useCallback(() => setMention(null), []);
|
|
350
|
+
const graphShown = !useIsMobile(1024) || view === "graph";
|
|
351
|
+
const highlightMentionOf = marked && marked.source === selectedPageId ? marked.target : void 0;
|
|
352
|
+
const selected = source.usePage(selectedPageId);
|
|
353
|
+
const lazy = useLazyTree(source, graph, selected.data);
|
|
354
|
+
const showPage = view === "page" && !!selectedPageId;
|
|
355
|
+
const openPage = (pageId) => {
|
|
356
|
+
onSelect(pageId);
|
|
357
|
+
onViewChange("page");
|
|
358
|
+
};
|
|
359
|
+
const selectFromTree = (page) => {
|
|
360
|
+
if (page.isScope) setFocusScopeId(page.id);
|
|
361
|
+
if (view === "graph") onSelect(page.id);
|
|
362
|
+
else openPage(page.id);
|
|
363
|
+
};
|
|
364
|
+
const openAnywhere = (pageId) => {
|
|
365
|
+
if (focusScopeId && !withinScope([...lazy.pages, ...graph.pages], focusScopeId).some((page) => page.id === pageId)) setFocusScopeId(null);
|
|
366
|
+
openPage(pageId);
|
|
367
|
+
};
|
|
368
|
+
const focusScope = focusScopeId ? lazy.pages.find((page) => page.id === focusScopeId) ?? pagesById.get(focusScopeId) : void 0;
|
|
369
|
+
const treePages = withinScope(source.useTreeLevels ? lazy.pages : graph.pages, focusScope ? focusScopeId : null);
|
|
370
|
+
const graphPages = useMemo(() => withinScope(graph.pages, focusScope ? focusScopeId : null), [
|
|
371
|
+
graph.pages,
|
|
372
|
+
focusScope,
|
|
373
|
+
focusScopeId
|
|
374
|
+
]);
|
|
375
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
376
|
+
className: "flex min-h-0 flex-1 flex-col gap-3",
|
|
377
|
+
children: [
|
|
378
|
+
/* @__PURE__ */ jsxs("div", {
|
|
379
|
+
className: "flex flex-wrap items-center gap-2",
|
|
380
|
+
children: [/* @__PURE__ */ jsx(SearchBox, {
|
|
381
|
+
source,
|
|
382
|
+
onSelect: openAnywhere
|
|
383
|
+
}), /* @__PURE__ */ jsx("div", {
|
|
384
|
+
role: "group",
|
|
385
|
+
"aria-label": "View",
|
|
386
|
+
className: "flex rounded border border-border",
|
|
387
|
+
children: [
|
|
388
|
+
{
|
|
389
|
+
value: "tree",
|
|
390
|
+
label: "Tree",
|
|
391
|
+
narrowOnly: true
|
|
392
|
+
},
|
|
393
|
+
{
|
|
394
|
+
value: "graph",
|
|
395
|
+
label: "Graph"
|
|
396
|
+
},
|
|
397
|
+
{
|
|
398
|
+
value: "page",
|
|
399
|
+
label: "Page"
|
|
400
|
+
}
|
|
401
|
+
].map((option) => /* @__PURE__ */ jsx("button", {
|
|
402
|
+
type: "button",
|
|
403
|
+
"aria-pressed": option.value === "page" ? showPage : option.value === "graph" ? !showPage && view !== "tree" : view === "tree",
|
|
404
|
+
disabled: option.value === "page" && !selectedPageId,
|
|
405
|
+
className: `text-ui-md px-3 py-1 disabled:opacity-50 aria-pressed:bg-muted ${option.narrowOnly ? "lg:hidden" : ""}`,
|
|
406
|
+
onClick: () => onViewChange(option.value),
|
|
407
|
+
children: option.label
|
|
408
|
+
}, option.value))
|
|
409
|
+
})]
|
|
410
|
+
}),
|
|
411
|
+
graph.truncated && !showPage ? /* @__PURE__ */ jsxs("p", {
|
|
412
|
+
className: "text-ui-sm text-muted-foreground",
|
|
413
|
+
children: [
|
|
414
|
+
"The graph shows the first ",
|
|
415
|
+
graph.pages.length,
|
|
416
|
+
" pages. Open the tree or search to reach the rest."
|
|
417
|
+
]
|
|
418
|
+
}) : null,
|
|
419
|
+
selectedPageId && !showPage && isNotFound(selected.error) ? /* @__PURE__ */ jsx("p", {
|
|
420
|
+
role: "alert",
|
|
421
|
+
className: "text-ui-sm text-destructive-foreground",
|
|
422
|
+
children: "Page not found. The linked page may have been deleted or merged."
|
|
423
|
+
}) : null,
|
|
424
|
+
/* @__PURE__ */ jsxs("div", {
|
|
425
|
+
className: "flex min-h-0 flex-1 flex-col gap-3 lg:flex-row",
|
|
426
|
+
children: [/* @__PURE__ */ jsxs("aside", {
|
|
427
|
+
className: `min-h-0 w-full flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card lg:flex lg:w-72 lg:flex-none lg:shrink-0 ${view === "tree" ? "flex" : "hidden"}`,
|
|
428
|
+
children: [focusScope ? /* @__PURE__ */ jsxs("div", {
|
|
429
|
+
className: "flex items-center gap-2 border-b border-border bg-fill-subtle px-3 py-2",
|
|
430
|
+
"data-testid": "knowledge-scope-focus",
|
|
431
|
+
children: [/* @__PURE__ */ jsxs("div", {
|
|
432
|
+
className: "flex min-w-0 flex-1 flex-col",
|
|
433
|
+
children: [/* @__PURE__ */ jsx(Txt, {
|
|
434
|
+
as: "span",
|
|
435
|
+
variant: "eyebrow",
|
|
436
|
+
tone: "muted",
|
|
437
|
+
className: "uppercase",
|
|
438
|
+
children: focusScope.displayLabel ?? "Scope"
|
|
439
|
+
}), /* @__PURE__ */ jsx(Txt, {
|
|
440
|
+
as: "span",
|
|
441
|
+
variant: "label",
|
|
442
|
+
tone: "ink",
|
|
443
|
+
className: "truncate",
|
|
444
|
+
children: focusScope.address ?? focusScope.name
|
|
445
|
+
})]
|
|
446
|
+
}), /* @__PURE__ */ jsx("button", {
|
|
447
|
+
type: "button",
|
|
448
|
+
className: "text-ui-sm shrink-0 rounded px-2 py-1 text-muted-foreground hover:bg-fill hover:text-foreground",
|
|
449
|
+
onClick: () => setFocusScopeId(null),
|
|
450
|
+
children: "All scopes"
|
|
451
|
+
})]
|
|
452
|
+
}) : null, /* @__PURE__ */ jsx("div", {
|
|
453
|
+
className: "min-h-0 flex-1 overflow-auto",
|
|
454
|
+
children: source.useTreeLevels && lazy.rootsPending ? /* @__PURE__ */ jsx("p", {
|
|
455
|
+
className: "px-3 py-2 text-body text-muted-foreground",
|
|
456
|
+
children: "Loading pages…"
|
|
457
|
+
}) : /* @__PURE__ */ jsx(KnowledgePageTree, {
|
|
458
|
+
pages: treePages,
|
|
459
|
+
pinnedIds: graph.pinnedIds,
|
|
460
|
+
selectedPageId,
|
|
461
|
+
onSelect: selectFromTree,
|
|
462
|
+
initiallyExpanded: focusScope ? [focusScope.id] : void 0,
|
|
463
|
+
...source.useTreeLevels ? {
|
|
464
|
+
mayHaveChildren: lazy.mayHaveChildren,
|
|
465
|
+
onExpandedChange: lazy.onExpandedChange,
|
|
466
|
+
loadMore: lazy.loadMore
|
|
467
|
+
} : {}
|
|
468
|
+
}, focusScope ? focusScope.id : "all")
|
|
469
|
+
})]
|
|
470
|
+
}), showPage ? /* @__PURE__ */ jsx("section", {
|
|
471
|
+
"aria-label": "Selected page",
|
|
472
|
+
className: "min-h-0 min-w-0 flex-1 overflow-auto rounded-lg border border-border bg-card",
|
|
473
|
+
children: /* @__PURE__ */ jsx(SelectedPage, {
|
|
474
|
+
source,
|
|
475
|
+
pageId: selectedPageId,
|
|
476
|
+
pagesById,
|
|
477
|
+
onSelect: openAnywhere,
|
|
478
|
+
highlightMentionOf
|
|
479
|
+
})
|
|
480
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
481
|
+
className: `relative min-h-0 min-w-0 flex-1 overflow-hidden rounded-lg border border-border bg-background lg:block lg:h-full ${view === "graph" ? "block" : "hidden"}`,
|
|
482
|
+
"data-testid": "knowledge-graph-container",
|
|
483
|
+
children: [graphShown ? /* @__PURE__ */ jsx(KnowledgePageGraph, {
|
|
484
|
+
pages: graphPages,
|
|
485
|
+
edges: mentionEdges,
|
|
486
|
+
pinnedIds: graph.pinnedIds,
|
|
487
|
+
grants: graph.grants,
|
|
488
|
+
selectedPageId,
|
|
489
|
+
onSelect: (page) => {
|
|
490
|
+
onSelect(page.id);
|
|
491
|
+
if (view !== "graph") onViewChange("graph");
|
|
492
|
+
},
|
|
493
|
+
onOpen: (page) => openPage(page.id),
|
|
494
|
+
onClearSelection: () => {
|
|
495
|
+
setMention(null);
|
|
496
|
+
if (selectedPageId) onSelect(null);
|
|
497
|
+
},
|
|
498
|
+
onMentionSelect: setMention
|
|
499
|
+
}) : null, mention && graphShown ? /* @__PURE__ */ jsx(MentionPopup, {
|
|
500
|
+
source,
|
|
501
|
+
mention,
|
|
502
|
+
pagesById,
|
|
503
|
+
onClose: closeMention,
|
|
504
|
+
onOpen: (pageId) => {
|
|
505
|
+
setMarked(pageId === mention.source.id ? {
|
|
506
|
+
source: mention.source.id,
|
|
507
|
+
target: mention.target.id
|
|
508
|
+
} : null);
|
|
509
|
+
setMention(null);
|
|
510
|
+
openAnywhere(pageId);
|
|
511
|
+
}
|
|
512
|
+
}) : null]
|
|
513
|
+
})]
|
|
514
|
+
})
|
|
515
|
+
]
|
|
516
|
+
});
|
|
517
|
+
}
|
|
518
|
+
export { KnowledgePageExplorer };
|
|
519
|
+
|
|
520
|
+
//# sourceMappingURL=KnowledgePageExplorer.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"KnowledgePageExplorer.es.js","names":["_Fragment"],"sources":["../../../../src/domains/knowledge/components/KnowledgePageExplorer.tsx"],"sourcesContent":["import { X } from 'lucide-react';\nimport { useCallback, useEffect, useMemo, useState } from 'react';\n\nimport { mentionPopupPlacement } from '../lib/popupPlacement';\n\nimport type {\n KnowledgePageActivityPayload,\n KnowledgeNotePayload,\n KnowledgePageEdge,\n KnowledgePagePayload,\n KnowledgePinPayload,\n KnowledgeScopeGrantPayload,\n} from '../pageTypes';\nimport { KnowledgeNoteItem, KnowledgePageDetail } from './KnowledgePageDetail';\nimport { KnowledgePageGraph } from './KnowledgePageGraph';\nimport { KNOWLEDGE_TREE_ROOT, KnowledgePageTree } from './KnowledgePageTree';\n\nimport { EmptyState } from '@/ds/components/EmptyState';\nimport { Txt } from '@/ds/components/Txt';\nimport { useIsMobile } from '@/hooks/use-is-mobile';\n\n/** `tree` is only a choice below `lg`; wider screens always show the tree beside the graph or the page. */\nexport type KnowledgeExplorerView = 'tree' | 'graph' | 'page';\n\n/** The bounded page graph a host loads. Without `useTreeLevels`, its pages also feed the tree. */\nexport interface KnowledgeExplorerGraph {\n pages: KnowledgePagePayload[];\n edges: KnowledgePageEdge[];\n pinnedIds: string[];\n /** Access grants between scopes; hosts whose server doesn't send them leave this out. */\n grants?: KnowledgeScopeGrantPayload[];\n truncated: boolean;\n}\n\nexport interface KnowledgeExplorerPageDetail {\n page: KnowledgePagePayload;\n notes: KnowledgeNotePayload[];\n /** Cursor for the page's next notes. */\n notesNextCursor?: string;\n pin?: KnowledgePinPayload | null;\n /** Ancestors and referenced pages, which may sit outside the loaded graph. */\n ancestors: KnowledgePagePayload[];\n related: KnowledgePagePayload[];\n /** Notes on other pages that mention this one. */\n mentionedBy?: KnowledgeNotePayload[];\n}\n\n/** One level of the tree: a parent's child scopes then its child pages, paged. */\nexport interface KnowledgeExplorerTreeLevel {\n pages: KnowledgePagePayload[];\n nextCursor?: string;\n}\n\nexport interface KnowledgeExplorerActivity {\n events: KnowledgePageActivityPayload[];\n}\n\nexport interface KnowledgeExplorerQueryState<T> {\n data?: T;\n isPending: boolean;\n isError: boolean;\n error: Error | null;\n}\n\n/** One request for a tree level: `parentId: null` for the root scopes. */\nexport interface KnowledgeExplorerTreeRequest {\n parentId: string | null;\n cursor?: string;\n}\n\n/**\n * Host data hooks. Each host binds them to its own routes (Studio to the Mastra client, Factory to its\n * project-scoped routes), so the explorer never knows a URL or an id outside the page ids it shows.\n * Pass the same functions every render: they are called as hooks.\n */\nexport interface KnowledgeExplorerSource {\n /** One page; `noteCursor` fetches a later page of its notes. Disabled when `pageId` is null. */\n usePage: (pageId: string | null, noteCursor?: string) => KnowledgeExplorerQueryState<KnowledgeExplorerPageDetail>;\n useSearch: (query: string) => { data?: { results: Array<{ page: KnowledgePagePayload }> } };\n /** Tree levels, one result per request in order (e.g. `useQueries`). Enables the lazily loaded tree and child pages. */\n useTreeLevels?: (\n requests: KnowledgeExplorerTreeRequest[],\n ) => Array<KnowledgeExplorerQueryState<KnowledgeExplorerTreeLevel>>;\n /** A page's recent activity, newest first. */\n useActivity?: (pageId: string) => KnowledgeExplorerQueryState<KnowledgeExplorerActivity>;\n}\n\nexport interface KnowledgePageExplorerProps {\n graph: KnowledgeExplorerGraph;\n source: KnowledgeExplorerSource;\n selectedPageId: string | null;\n /** `null` clears the selection: a click on empty graph canvas. */\n onSelect: (pageId: string | null) => void;\n view: KnowledgeExplorerView;\n onViewChange: (view: KnowledgeExplorerView) => void;\n}\n\nconst MIN_SEARCH_LENGTH = 2;\nconst noTreeLevels = () => [];\nconst noActivity = (): KnowledgeExplorerQueryState<KnowledgeExplorerActivity> => ({\n isPending: false,\n isError: false,\n error: null,\n});\n\nfunction isNotFound(error: unknown): boolean {\n return !!error && typeof error === 'object' && 'status' in error && error.status === 404;\n}\n\nfunction withPages(\n base: ReadonlyMap<string, KnowledgePagePayload>,\n pages: KnowledgePagePayload[],\n): ReadonlyMap<string, KnowledgePagePayload> {\n if (pages.length === 0) return base;\n const merged = new Map(base);\n for (const page of pages) merged.set(page.id, page);\n return merged;\n}\n\n/** `pages` narrowed to `scopeId` and everything below it, following parent links among the given pages. */\nfunction withinScope(pages: KnowledgePagePayload[], scopeId: string | null): KnowledgePagePayload[] {\n if (!scopeId) return pages;\n const byId = new Map(pages.map(page => [page.id, page]));\n const inside = new Map<string, boolean>([[scopeId, true]]);\n const isInside = (page: KnowledgePagePayload): boolean => {\n const known = inside.get(page.id);\n if (known !== undefined) return known;\n const parent = page.parentId ? byId.get(page.parentId) : undefined;\n inside.set(page.id, false);\n const result = !!parent && parent.id !== page.id && isInside(parent);\n inside.set(page.id, result);\n return result;\n };\n return pages.filter(isInside);\n}\n\nfunction MoreButton({ onClick, label = 'Load more' }: { onClick: () => void; label?: string }) {\n return (\n <button\n type=\"button\"\n className=\"self-start text-caption text-muted-foreground hover:text-foreground\"\n onClick={onClick}\n >\n {label}\n </button>\n );\n}\n\n/** The next page of a page's notes, then a button for the one after. */\nfunction MoreNotes({\n source,\n pageId,\n cursor,\n pagesById,\n onPageClick,\n}: {\n source: KnowledgeExplorerSource;\n pageId: string;\n cursor: string;\n pagesById: ReadonlyMap<string, KnowledgePagePayload>;\n onPageClick: (page: KnowledgePagePayload) => void;\n}) {\n const chunk = source.usePage(pageId, cursor);\n const [showNext, setShowNext] = useState(false);\n const known = useMemo(() => withPages(pagesById, chunk.data?.related ?? []), [chunk.data, pagesById]);\n if (chunk.isPending) return <p className=\"text-caption text-muted-foreground\">Loading notes…</p>;\n if (!chunk.data) return null;\n const next = chunk.data.notesNextCursor;\n return (\n <>\n <ul className=\"flex flex-col gap-3\">\n {chunk.data.notes.map(note => (\n <KnowledgeNoteItem key={note.id} note={note} pagesById={known} onPageClick={onPageClick} />\n ))}\n </ul>\n {next ? (\n showNext ? (\n <MoreNotes source={source} pageId={pageId} cursor={next} pagesById={pagesById} onPageClick={onPageClick} />\n ) : (\n <MoreButton label=\"Load more notes\" onClick={() => setShowNext(true)} />\n )\n ) : null}\n </>\n );\n}\n\n/** A page's children, a page at a time. */\nfunction ChildPages({\n useTreeLevels,\n parentId,\n onPageClick,\n}: {\n useTreeLevels: NonNullable<KnowledgeExplorerSource['useTreeLevels']>;\n parentId: string;\n onPageClick: (page: KnowledgePagePayload) => void;\n}) {\n const [cursors, setCursors] = useState<string[]>([]);\n const requests = useMemo(() => [{ parentId }, ...cursors.map(cursor => ({ parentId, cursor }))], [parentId, cursors]);\n const levels = useTreeLevels(requests);\n const pages = levels.flatMap(level => level.data?.pages ?? []);\n const last = levels[levels.length - 1];\n if (levels[0]?.isPending) return <p className=\"text-caption text-muted-foreground\">Loading pages…</p>;\n if (pages.length === 0) {\n return (\n <p className=\"text-body text-muted-foreground\" data-testid=\"knowledge-no-child-pages\">\n No pages under this one.\n </p>\n );\n }\n const next = last?.data?.nextCursor;\n return (\n <>\n <ul className=\"flex flex-col gap-1\">\n {pages.map(child => (\n <li key={child.id} className=\"flex flex-col\">\n <button\n type=\"button\"\n className=\"text-left text-body font-medium text-info-indicator hover:underline\"\n onClick={() => onPageClick(child)}\n >\n {child.name}\n </button>\n {child.description ? (\n <span className=\"truncate text-caption text-muted-foreground\">{child.description}</span>\n ) : null}\n </li>\n ))}\n </ul>\n {next ? <MoreButton onClick={() => setCursors(current => [...current, next])} /> : null}\n </>\n );\n}\n\ninterface MentionSelection {\n source: KnowledgePagePayload;\n target: KnowledgePagePayload;\n point: { x: number; y: number };\n pane: { width: number; height: number };\n}\n\n/** What a clicked mention line stands for: the notes on one page that mention the other. */\nfunction MentionPopup({\n source,\n mention,\n pagesById,\n onOpen,\n onClose,\n}: {\n source: KnowledgeExplorerSource;\n mention: MentionSelection;\n pagesById: ReadonlyMap<string, KnowledgePagePayload>;\n onOpen: (pageId: string) => void;\n onClose: () => void;\n}) {\n const detail = source.usePage(mention.source.id);\n const notes = (detail.data?.notes ?? []).filter(note => note.mentions.includes(mention.target.id));\n useEffect(() => {\n const onKey = (event: KeyboardEvent) => {\n if (event.key === 'Escape') onClose();\n };\n window.addEventListener('keydown', onKey);\n return () => window.removeEventListener('keydown', onKey);\n }, [onClose]);\n return (\n <div\n role=\"dialog\"\n aria-label={`${mention.source.name} mentions ${mention.target.name}`}\n data-testid=\"knowledge-mention-popup\"\n className=\"absolute z-20 flex w-80 max-w-[calc(100%-1rem)] flex-col gap-2 overflow-hidden rounded-lg border border-border bg-card p-3 shadow-overlay\"\n style={mentionPopupPlacement(mention)}\n >\n <div className=\"flex items-start gap-2\">\n <Txt as=\"h3\" variant=\"card-title\" className=\"min-w-0 flex-1\">\n <button type=\"button\" className=\"hover:underline\" onClick={() => onOpen(mention.source.id)}>\n {mention.source.name}\n </button>\n <Txt as=\"span\" variant=\"card-title\" tone=\"muted\">\n {' '}\n mentions{' '}\n </Txt>\n <button type=\"button\" className=\"hover:underline\" onClick={() => onOpen(mention.target.id)}>\n {mention.target.name}\n </button>\n </Txt>\n <button\n type=\"button\"\n aria-label=\"Close\"\n className=\"rounded p-0.5 text-muted-foreground hover:bg-fill hover:text-foreground\"\n onClick={onClose}\n >\n <X size={14} aria-hidden />\n </button>\n </div>\n <div className=\"min-h-0 overflow-y-auto\">\n {detail.isPending ? (\n <Txt variant=\"caption\" tone=\"muted\">\n Loading notes…\n </Txt>\n ) : notes.length === 0 ? (\n <Txt variant=\"caption\" tone=\"muted\">\n The notes that make this mention aren't in the first page of notes. Open {mention.source.name} to read them\n all.\n </Txt>\n ) : (\n <ul className=\"flex flex-col gap-2\">\n {notes.map(note => (\n <KnowledgeNoteItem\n key={note.id}\n note={note}\n pagesById={withPages(pagesById, detail.data?.related ?? [])}\n onPageClick={page => onOpen(page.id)}\n compact\n />\n ))}\n </ul>\n )}\n </div>\n </div>\n );\n}\n\nfunction SelectedPage({\n source,\n pageId,\n pagesById,\n onSelect,\n highlightMentionOf,\n}: {\n source: KnowledgeExplorerSource;\n pageId: string;\n pagesById: ReadonlyMap<string, KnowledgePagePayload>;\n onSelect: (pageId: string) => void;\n highlightMentionOf?: string;\n}) {\n const detail = source.usePage(pageId);\n const activity = (source.useActivity ?? noActivity)(pageId);\n const [moreNotes, setMoreNotes] = useState<{ pageId: string } | null>(null);\n const known = useMemo(\n () => (detail.data ? withPages(pagesById, [...detail.data.ancestors, ...detail.data.related]) : pagesById),\n [detail.data, pagesById],\n );\n\n if (detail.isPending) return <p className=\"text-ui-md p-4 text-muted-foreground\">Loading page…</p>;\n if (detail.isError || !detail.data) {\n const notFound = isNotFound(detail.error);\n return (\n <EmptyState\n tone=\"error\"\n variant=\"fill\"\n titleSlot={notFound ? 'Page not found' : 'Failed to load the page'}\n descriptionSlot={notFound ? 'It may have been deleted or merged.' : (detail.error?.message ?? '')}\n />\n );\n }\n const onPageClick = (page: KnowledgePagePayload) => onSelect(page.id);\n const next = detail.data.notesNextCursor;\n return (\n <KnowledgePageDetail\n page={detail.data.page}\n notes={detail.data.notes}\n pin={detail.data.pin ?? undefined}\n pagesById={known}\n onPageClick={onPageClick}\n highlightMentionOf={highlightMentionOf}\n ancestors={detail.data.ancestors}\n mentionedBy={detail.data.mentionedBy}\n activity={activity.data?.events}\n childPages={\n source.useTreeLevels ? (\n <ChildPages key={pageId} useTreeLevels={source.useTreeLevels} parentId={pageId} onPageClick={onPageClick} />\n ) : undefined\n }\n notesMore={\n next ? (\n moreNotes?.pageId === pageId ? (\n <MoreNotes source={source} pageId={pageId} cursor={next} pagesById={known} onPageClick={onPageClick} />\n ) : (\n <MoreButton label=\"Load more notes\" onClick={() => setMoreNotes({ pageId })} />\n )\n ) : undefined\n }\n />\n );\n}\n\nfunction SearchBox({ source, onSelect }: { source: KnowledgeExplorerSource; onSelect: (pageId: string) => void }) {\n const [query, setQuery] = useState('');\n const search = source.useSearch(query);\n const results = query.trim().length >= MIN_SEARCH_LENGTH ? (search.data?.results ?? []) : [];\n const seen = new Set<string>();\n const pages = results\n .map(hit => hit.page)\n .filter(page => (seen.has(page.id) ? false : (seen.add(page.id), true)))\n .slice(0, 10);\n return (\n <div className=\"relative min-w-60 flex-1\">\n <input\n aria-label=\"Search knowledge\"\n placeholder=\"Search pages and notes\"\n className=\"text-ui-md h-8 w-full rounded border border-border bg-card px-2\"\n value={query}\n onChange={event => setQuery(event.target.value)}\n />\n {pages.length > 0 ? (\n <ul\n role=\"listbox\"\n aria-label=\"Search results\"\n className=\"absolute z-20 mt-1 max-h-72 w-full overflow-auto rounded border border-border bg-card shadow-raised\"\n >\n {pages.map(page => (\n <li key={page.id} role=\"option\" aria-selected={false}>\n <button\n type=\"button\"\n className=\"text-ui-md w-full px-2 py-1.5 text-left hover:bg-muted\"\n onClick={() => {\n onSelect(page.id);\n setQuery('');\n }}\n >\n {page.name}\n </button>\n </li>\n ))}\n </ul>\n ) : null}\n </div>\n );\n}\n\n/**\n * The tree loaded a level at a time through `useTreeLevels`: the root scopes, then each level as it is\n * opened, plus the path to the selected page. Unloaded pages keep a chevron until opened.\n */\nfunction useLazyTree(\n source: KnowledgeExplorerSource,\n graph: KnowledgeExplorerGraph,\n selected: KnowledgeExplorerPageDetail | undefined,\n) {\n const [expanded, setExpanded] = useState<ReadonlySet<string>>(() => new Set());\n const [more, setMore] = useState<ReadonlyMap<string, string[]>>(() => new Map());\n const requests = useMemo(() => {\n const list: KnowledgeExplorerTreeRequest[] = [{ parentId: null }];\n for (const id of expanded) {\n list.push({ parentId: id });\n for (const cursor of more.get(id) ?? []) list.push({ parentId: id, cursor });\n }\n return list;\n }, [expanded, more]);\n const levels = (source.useTreeLevels ?? noTreeLevels)(requests);\n\n const { pages, loaded, nextCursor } = useMemo(() => {\n const byId = new Map<string, KnowledgePagePayload>();\n const loadedIds = new Set<string>();\n const next = new Map<string, string>();\n levels.forEach((level, index) => {\n const request = requests[index];\n if (!request || !level.data) return;\n const key = request.parentId ?? KNOWLEDGE_TREE_ROOT;\n loadedIds.add(key);\n for (const page of level.data.pages) byId.set(page.id, page);\n if (level.data.nextCursor) next.set(key, level.data.nextCursor);\n else next.delete(key);\n });\n // The selected page and its path, so the tree can open down to a page outside the loaded levels.\n for (const page of [...(selected?.ancestors ?? []), ...(selected ? [selected.page] : [])]) {\n if (!byId.has(page.id)) byId.set(page.id, page);\n }\n return { pages: [...byId.values()], loaded: loadedIds, nextCursor: next };\n }, [levels, requests, selected]);\n\n // With the whole graph loaded, its structure is complete: only pages with children get a chevron.\n const graphParents = useMemo(\n () => (graph.truncated ? null : new Set(graph.pages.map(page => page.parentId).filter(id => id !== null))),\n [graph],\n );\n const mayHaveChildren = useCallback(\n (page: KnowledgePagePayload) => !loaded.has(page.id) && (graphParents ? graphParents.has(page.id) : true),\n [loaded, graphParents],\n );\n const loadMore = useMemo(() => {\n const map = new Map<string, () => void>();\n for (const [parentId, cursor] of nextCursor) {\n map.set(parentId, () =>\n setMore(current => new Map(current).set(parentId, [...(current.get(parentId) ?? []), cursor])),\n );\n }\n return map;\n }, [nextCursor]);\n const onExpandedChange = useCallback((ids: ReadonlySet<string>) => setExpanded(new Set(ids)), []);\n\n return { pages, mayHaveChildren, loadMore, onExpandedChange, rootsPending: levels[0]?.isPending ?? false };\n}\n\n/**\n * Search, the page tree, and either the page graph or the selected page, kept in sync on one selection.\n * Wide screens show the tree beside the graph or the page; below `lg` one toggle picks tree, graph or page.\n * A first click on a page in the graph selects it; clicking it again opens it as a page. A search result\n * opens it as a page straight away. Selecting in the tree keeps the current view, so the graph frames the\n * page instead.\n */\nexport function KnowledgePageExplorer({\n graph,\n source,\n selectedPageId,\n onSelect,\n view,\n onViewChange,\n}: KnowledgePageExplorerProps) {\n const pagesById = useMemo(() => new Map(graph.pages.map(page => [page.id, page])), [graph.pages]);\n // A scope picked in the tree narrows the tree and the graph to that scope and what sits under it.\n const [focusScopeId, setFocusScopeId] = useState<string | null>(null);\n const mentionEdges = useMemo(() => graph.edges.filter(edge => edge.kind === 'mention'), [graph.edges]);\n // A clicked mention line shows the notes that make the mention; opening the page from there marks them.\n const [mention, setMention] = useState<MentionSelection | null>(null);\n const [marked, setMarked] = useState<{ source: string; target: string } | null>(null);\n const closeMention = useCallback(() => setMention(null), []);\n // Below lg the graph shares its slot with the tree. Mount it only when it is showing: a graph mounted\n // into a hidden 0×0 pane has nothing to fit and was left unfitted when the toggle revealed it.\n const narrow = useIsMobile(1024);\n const graphShown = !narrow || view === 'graph';\n const highlightMentionOf = marked && marked.source === selectedPageId ? marked.target : undefined;\n const selected = source.usePage(selectedPageId);\n const lazy = useLazyTree(source, graph, selected.data);\n const showPage = view === 'page' && !!selectedPageId;\n const openPage = (pageId: string) => {\n onSelect(pageId);\n onViewChange('page');\n };\n // From the tree: frame the page in the graph when the graph is up, otherwise open it.\n const selectFromTree = (page: KnowledgePagePayload) => {\n if (page.isScope) setFocusScopeId(page.id);\n if (view === 'graph') onSelect(page.id);\n else openPage(page.id);\n };\n // Pages reached from outside the tree (search, links, mentions) clear a focus they fall outside of.\n const openAnywhere = (pageId: string) => {\n if (focusScopeId && !withinScope([...lazy.pages, ...graph.pages], focusScopeId).some(page => page.id === pageId)) {\n setFocusScopeId(null);\n }\n openPage(pageId);\n };\n const focusScope = focusScopeId\n ? (lazy.pages.find(page => page.id === focusScopeId) ?? pagesById.get(focusScopeId))\n : undefined;\n const treePages = withinScope(source.useTreeLevels ? lazy.pages : graph.pages, focusScope ? focusScopeId : null);\n const graphPages = useMemo(\n () => withinScope(graph.pages, focusScope ? focusScopeId : null),\n [graph.pages, focusScope, focusScopeId],\n );\n const views: Array<{ value: KnowledgeExplorerView; label: string; narrowOnly?: boolean }> = [\n { value: 'tree', label: 'Tree', narrowOnly: true },\n { value: 'graph', label: 'Graph' },\n { value: 'page', label: 'Page' },\n ];\n\n return (\n <div className=\"flex min-h-0 flex-1 flex-col gap-3\">\n <div className=\"flex flex-wrap items-center gap-2\">\n <SearchBox source={source} onSelect={openAnywhere} />\n <div role=\"group\" aria-label=\"View\" className=\"flex rounded border border-border\">\n {views.map(option => (\n <button\n key={option.value}\n type=\"button\"\n aria-pressed={\n option.value === 'page'\n ? showPage\n : option.value === 'graph'\n ? !showPage && view !== 'tree'\n : view === 'tree'\n }\n disabled={option.value === 'page' && !selectedPageId}\n className={`text-ui-md px-3 py-1 disabled:opacity-50 aria-pressed:bg-muted ${option.narrowOnly ? 'lg:hidden' : ''}`}\n onClick={() => onViewChange(option.value)}\n >\n {option.label}\n </button>\n ))}\n </div>\n </div>\n {graph.truncated && !showPage ? (\n <p className=\"text-ui-sm text-muted-foreground\">\n The graph shows the first {graph.pages.length} pages. Open the tree or search to reach the rest.\n </p>\n ) : null}\n {selectedPageId && !showPage && isNotFound(selected.error) ? (\n <p role=\"alert\" className=\"text-ui-sm text-destructive-foreground\">\n Page not found. The linked page may have been deleted or merged.\n </p>\n ) : null}\n <div className=\"flex min-h-0 flex-1 flex-col gap-3 lg:flex-row\">\n <aside\n className={`min-h-0 w-full flex-1 flex-col overflow-hidden rounded-lg border border-border bg-card lg:flex lg:w-72 lg:flex-none lg:shrink-0 ${view === 'tree' ? 'flex' : 'hidden'}`}\n >\n {focusScope ? (\n <div\n className=\"flex items-center gap-2 border-b border-border bg-fill-subtle px-3 py-2\"\n data-testid=\"knowledge-scope-focus\"\n >\n <div className=\"flex min-w-0 flex-1 flex-col\">\n <Txt as=\"span\" variant=\"eyebrow\" tone=\"muted\" className=\"uppercase\">\n {focusScope.displayLabel ?? 'Scope'}\n </Txt>\n <Txt as=\"span\" variant=\"label\" tone=\"ink\" className=\"truncate\">\n {focusScope.address ?? focusScope.name}\n </Txt>\n </div>\n <button\n type=\"button\"\n className=\"text-ui-sm shrink-0 rounded px-2 py-1 text-muted-foreground hover:bg-fill hover:text-foreground\"\n onClick={() => setFocusScopeId(null)}\n >\n All scopes\n </button>\n </div>\n ) : null}\n <div className=\"min-h-0 flex-1 overflow-auto\">\n {source.useTreeLevels && lazy.rootsPending ? (\n <p className=\"px-3 py-2 text-body text-muted-foreground\">Loading pages…</p>\n ) : (\n <KnowledgePageTree\n key={focusScope ? focusScope.id : 'all'}\n pages={treePages}\n pinnedIds={graph.pinnedIds}\n selectedPageId={selectedPageId}\n onSelect={selectFromTree}\n initiallyExpanded={focusScope ? [focusScope.id] : undefined}\n {...(source.useTreeLevels\n ? {\n mayHaveChildren: lazy.mayHaveChildren,\n onExpandedChange: lazy.onExpandedChange,\n loadMore: lazy.loadMore,\n }\n : {})}\n />\n )}\n </div>\n </aside>\n {showPage ? (\n <section\n aria-label=\"Selected page\"\n className=\"min-h-0 min-w-0 flex-1 overflow-auto rounded-lg border border-border bg-card\"\n >\n <SelectedPage\n source={source}\n pageId={selectedPageId}\n pagesById={pagesById}\n onSelect={openAnywhere}\n highlightMentionOf={highlightMentionOf}\n />\n </section>\n ) : (\n <div\n className={`relative min-h-0 min-w-0 flex-1 overflow-hidden rounded-lg border border-border bg-background lg:block lg:h-full ${view === 'graph' ? 'block' : 'hidden'}`}\n data-testid=\"knowledge-graph-container\"\n >\n {graphShown ? (\n <KnowledgePageGraph\n pages={graphPages}\n edges={mentionEdges}\n pinnedIds={graph.pinnedIds}\n grants={graph.grants}\n selectedPageId={selectedPageId}\n onSelect={page => {\n onSelect(page.id);\n // Hosts resolve a `?page=` with no view to the page view, so say graph outright.\n if (view !== 'graph') onViewChange('graph');\n }}\n onOpen={page => openPage(page.id)}\n onClearSelection={() => {\n setMention(null);\n if (selectedPageId) onSelect(null);\n }}\n onMentionSelect={setMention}\n />\n ) : null}\n {mention && graphShown ? (\n <MentionPopup\n source={source}\n mention={mention}\n pagesById={pagesById}\n onClose={closeMention}\n onOpen={pageId => {\n setMarked(\n pageId === mention.source.id ? { source: mention.source.id, target: mention.target.id } : null,\n );\n setMention(null);\n openAnywhere(pageId);\n }}\n />\n ) : null}\n </div>\n )}\n </div>\n </div>\n );\n}\n"],"mappings":"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"}
|