@mastra/playground-ui 68.0.0-alpha.2 → 68.0.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/{FilterBar-CQl04O6t.cjs → FilterBar-BSP2UTjc.cjs} +2 -2
- package/dist/{FilterBar-CQl04O6t.cjs.map → FilterBar-BSP2UTjc.cjs.map} +1 -1
- package/dist/{FilterBar-BgW2dqRQ.js → FilterBar-PSQ1OwqH.js} +2 -2
- package/dist/{FilterBar-BgW2dqRQ.js.map → FilterBar-PSQ1OwqH.js.map} +1 -1
- package/dist/KnowledgePageGraph.css +55 -0
- package/dist/{MarkdownRenderer-2GOXQJEv.js → MarkdownRenderer-CI30RqdB.js} +19 -6
- package/dist/MarkdownRenderer-CI30RqdB.js.map +1 -0
- package/dist/{MarkdownRenderer-CB8Z_CHc.cjs → MarkdownRenderer-y65WGBhC.cjs} +19 -6
- package/dist/MarkdownRenderer-y65WGBhC.cjs.map +1 -0
- package/dist/{MetricsCard-CEB-f2sv.cjs → MetricsCard-BEwiS7Pe.cjs} +8 -8
- package/dist/MetricsCard-BEwiS7Pe.cjs.map +1 -0
- package/dist/{MetricsCard-M8awJ2B_.js → MetricsCard-ua6C6b8a.js} +10 -10
- package/dist/MetricsCard-ua6C6b8a.js.map +1 -0
- package/dist/{MetricsLineChart-BhHoduO0.js → MetricsLineChart-4SwxBbQx.js} +14 -3
- package/dist/MetricsLineChart-4SwxBbQx.js.map +1 -0
- package/dist/{MetricsLineChart-CjBm4IXu.cjs → MetricsLineChart-tZxsauau.cjs} +13 -2
- package/dist/MetricsLineChart-tZxsauau.cjs.map +1 -0
- package/dist/{MetricsStackedBarChart-BdMlKv6G.cjs → MetricsStackedBarChart-CDLE76IB.cjs} +2 -2
- package/dist/{MetricsStackedBarChart-BdMlKv6G.cjs.map → MetricsStackedBarChart-CDLE76IB.cjs.map} +1 -1
- package/dist/{MetricsStackedBarChart-BRuA6MTE.js → MetricsStackedBarChart-D2QyS4-z.js} +2 -2
- package/dist/{MetricsStackedBarChart-BRuA6MTE.js.map → MetricsStackedBarChart-D2QyS4-z.js.map} +1 -1
- package/dist/{activity-rJ1NQl_2.js → activity-C8Ql81WM.js} +2 -2
- package/dist/{activity-rJ1NQl_2.js.map → activity-C8Ql81WM.js.map} +1 -1
- package/dist/{activity-DyB5H3gF.cjs → activity-CcQZeDYi.cjs} +2 -2
- package/dist/{activity-DyB5H3gF.cjs.map → activity-CcQZeDYi.cjs.map} +1 -1
- package/dist/components/DateTimeRangePicker.cjs.js +1 -1
- package/dist/components/DateTimeRangePicker.es.js +1 -1
- package/dist/components/FilterBar.cjs.js +2 -2
- package/dist/components/FilterBar.es.js +2 -2
- package/dist/components/MarkdownRenderer.cjs.js +1 -1
- package/dist/components/MarkdownRenderer.es.js +1 -1
- package/dist/components/MetricsCard.cjs.js +1 -1
- package/dist/components/MetricsCard.es.js +1 -1
- package/dist/components/MetricsLineChart.cjs.js +1 -1
- package/dist/components/MetricsLineChart.es.js +1 -1
- package/dist/components/MetricsStackedBarChart.cjs.js +1 -1
- package/dist/components/MetricsStackedBarChart.es.js +1 -1
- package/dist/components/SavedViews.cjs.js +1 -1
- package/dist/components/SavedViews.es.js +1 -1
- package/dist/components/ai/activity.cjs.js +1 -1
- package/dist/components/ai/activity.es.js +1 -1
- package/dist/components/ai/plan.cjs.js +1 -1
- package/dist/components/ai/plan.es.js +1 -1
- 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/{date-time-range-picker-CTt7Od0P.cjs → date-time-range-picker-CWGjoR3j.cjs} +40 -13
- package/dist/date-time-range-picker-CWGjoR3j.cjs.map +1 -0
- package/dist/{date-time-range-picker-DKh1K9Iy.js → date-time-range-picker-CdSiXwB4.js} +40 -13
- package/dist/date-time-range-picker-CdSiXwB4.js.map +1 -0
- package/dist/domains/chat/activity/activity-stretch-line.cjs.js +1 -1
- package/dist/domains/chat/activity/activity-stretch-line.es.js +1 -1
- package/dist/domains/chat/activity/components/activity-fold.cjs.js +1 -1
- package/dist/domains/chat/activity/components/activity-fold.es.js +1 -1
- package/dist/domains/chat/activity/components/activity-timed-trigger.cjs.js +1 -1
- package/dist/domains/chat/activity/components/activity-timed-trigger.es.js +1 -1
- package/dist/domains/chat/activity/components/calls-panel.cjs.js +1 -1
- package/dist/domains/chat/activity/components/calls-panel.es.js +1 -1
- package/dist/domains/chat/activity/components/stretch-content.cjs.js +1 -1
- package/dist/domains/chat/activity/components/stretch-content.es.js +1 -1
- package/dist/domains/chat/activity/components/stretch-thought.cjs.js +1 -1
- package/dist/domains/chat/activity/components/stretch-thought.es.js +1 -1
- 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/components/badge-wrapper.cjs.js +1 -1
- package/dist/domains/chat/components/badge-wrapper.es.js +1 -1
- package/dist/domains/chat/knowledge/knowledge-links.cjs.js +52 -6
- package/dist/domains/chat/knowledge/knowledge-links.cjs.js.map +1 -1
- package/dist/domains/chat/knowledge/knowledge-links.es.js +53 -9
- package/dist/domains/chat/knowledge/knowledge-links.es.js.map +1 -1
- package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js +10 -3
- package/dist/domains/chat/knowledge/pinned-knowledge-data.cjs.js.map +1 -1
- package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js +10 -3
- package/dist/domains/chat/knowledge/pinned-knowledge-data.es.js.map +1 -1
- package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js +8 -3
- package/dist/domains/chat/knowledge/pinned-knowledge.cjs.js.map +1 -1
- package/dist/domains/chat/knowledge/pinned-knowledge.es.js +8 -3
- package/dist/domains/chat/knowledge/pinned-knowledge.es.js.map +1 -1
- package/dist/domains/chat/knowledge.cjs.js +2 -0
- package/dist/domains/chat/knowledge.es.js +2 -2
- package/dist/domains/chat/messages/message-row.cjs.js +3 -3
- package/dist/domains/chat/messages/message-row.es.js +3 -3
- package/dist/domains/chat/messages/notification-signal-notice.cjs.js +1 -1
- package/dist/domains/chat/messages/notification-signal-notice.es.js +1 -1
- package/dist/domains/chat/messages/reasoning-content.cjs.js +1 -1
- package/dist/domains/chat/messages/reasoning-content.es.js +1 -1
- package/dist/domains/chat/messages/renderers/message-text.cjs.js +35 -1
- package/dist/domains/chat/messages/renderers/message-text.cjs.js.map +1 -1
- package/dist/domains/chat/messages/renderers/message-text.es.js +36 -2
- package/dist/domains/chat/messages/renderers/message-text.es.js.map +1 -1
- package/dist/domains/chat/messages/renderers/reasoning-part-renderer.cjs.js +1 -1
- package/dist/domains/chat/messages/renderers/reasoning-part-renderer.es.js +1 -1
- package/dist/domains/chat/messages/signal-badge.cjs.js +1 -1
- package/dist/domains/chat/messages/signal-badge.es.js +1 -1
- package/dist/domains/chat/messages/skill-message.cjs.js +2 -2
- package/dist/domains/chat/messages/skill-message.es.js +2 -2
- package/dist/domains/chat/messages/system-reminder-badge.cjs.js +1 -1
- package/dist/domains/chat/messages/system-reminder-badge.es.js +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-body-range.cjs.js +80 -0
- package/dist/domains/chat/tools/badges/knowledge-body-range.cjs.js.map +1 -0
- package/dist/domains/chat/tools/badges/knowledge-body-range.d.ts +1 -0
- package/dist/domains/chat/tools/badges/knowledge-body-range.es.js +78 -0
- package/dist/domains/chat/tools/badges/knowledge-body-range.es.js.map +1 -0
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js +163 -13
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.cjs.js.map +1 -1
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js +165 -15
- package/dist/domains/chat/tools/badges/knowledge-tool-badge.es.js.map +1 -1
- package/dist/domains/chat/tools/badges/mcp-input-request-badge.cjs.js +51 -0
- package/dist/domains/chat/tools/badges/mcp-input-request-badge.cjs.js.map +1 -0
- package/dist/domains/chat/tools/badges/mcp-input-request-badge.d.ts +1 -0
- package/dist/domains/chat/tools/badges/mcp-input-request-badge.es.js +49 -0
- package/dist/domains/chat/tools/badges/mcp-input-request-badge.es.js.map +1 -0
- package/dist/domains/chat/tools/badges/mcp-task-chip.cjs.js +7 -2
- package/dist/domains/chat/tools/badges/mcp-task-chip.cjs.js.map +1 -1
- package/dist/domains/chat/tools/badges/mcp-task-chip.es.js +7 -2
- package/dist/domains/chat/tools/badges/mcp-task-chip.es.js.map +1 -1
- package/dist/domains/chat/tools/badges/observation-marker-badge.cjs.js +2 -2
- package/dist/domains/chat/tools/badges/observation-marker-badge.es.js +2 -2
- package/dist/domains/chat/tools/badges/observation-marker-details.cjs.js +2 -2
- package/dist/domains/chat/tools/badges/observation-marker-details.es.js +2 -2
- package/dist/domains/chat/tools/badges/observation-renderer.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/observation-renderer.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 +9 -4
- package/dist/domains/chat/tools/badges/tool-badge.cjs.js.map +1 -1
- package/dist/domains/chat/tools/badges/tool-badge.es.js +9 -4
- package/dist/domains/chat/tools/badges/tool-badge.es.js.map +1 -1
- package/dist/domains/chat/tools/badges/use-deferred-input-request.cjs.js +81 -0
- package/dist/domains/chat/tools/badges/use-deferred-input-request.cjs.js.map +1 -0
- package/dist/domains/chat/tools/badges/use-deferred-input-request.d.ts +1 -0
- package/dist/domains/chat/tools/badges/use-deferred-input-request.es.js +77 -0
- package/dist/domains/chat/tools/badges/use-deferred-input-request.es.js.map +1 -0
- package/dist/domains/chat/tools/badges/use-mcp-task-progress.cjs.js +11 -2
- package/dist/domains/chat/tools/badges/use-mcp-task-progress.cjs.js.map +1 -1
- package/dist/domains/chat/tools/badges/use-mcp-task-progress.es.js +11 -2
- package/dist/domains/chat/tools/badges/use-mcp-task-progress.es.js.map +1 -1
- package/dist/domains/chat/tools/badges/workflow-badge.cjs.js +1 -1
- package/dist/domains/chat/tools/badges/workflow-badge.es.js +1 -1
- package/dist/domains/chat/tools/connect-prompt-tool.cjs.js +79 -4
- package/dist/domains/chat/tools/connect-prompt-tool.cjs.js.map +1 -1
- package/dist/domains/chat/tools/connect-prompt-tool.es.js +79 -4
- package/dist/domains/chat/tools/connect-prompt-tool.es.js.map +1 -1
- package/dist/domains/chat/tools/mcp-input-request-tool.cjs.js +238 -0
- package/dist/domains/chat/tools/mcp-input-request-tool.cjs.js.map +1 -0
- package/dist/domains/chat/tools/mcp-input-request-tool.d.ts +1 -0
- package/dist/domains/chat/tools/mcp-input-request-tool.es.js +237 -0
- package/dist/domains/chat/tools/mcp-input-request-tool.es.js.map +1 -0
- package/dist/domains/chat/tools/mcp-input-request.cjs.js +40 -0
- package/dist/domains/chat/tools/mcp-input-request.cjs.js.map +1 -0
- package/dist/domains/chat/tools/mcp-input-request.d.ts +1 -0
- package/dist/domains/chat/tools/mcp-input-request.es.js +33 -0
- package/dist/domains/chat/tools/mcp-input-request.es.js.map +1 -0
- package/dist/domains/chat/tools/tool-card-kind.cjs.js +9 -4
- package/dist/domains/chat/tools/tool-card-kind.cjs.js.map +1 -1
- package/dist/domains/chat/tools/tool-card-kind.es.js +9 -5
- 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 +1 -1
- package/dist/domains/chat/tools/tool-groups.es.js +1 -1
- package/dist/domains/chat.cjs.js +5 -3
- package/dist/domains/chat.es.js +4 -4
- package/dist/domains/connect/types.cjs.js.map +1 -1
- package/dist/domains/connect/types.es.js.map +1 -1
- package/dist/domains/connect/use-user-connect.cjs.js +19 -2
- package/dist/domains/connect/use-user-connect.cjs.js.map +1 -1
- package/dist/domains/connect/use-user-connect.es.js +19 -2
- package/dist/domains/connect/use-user-connect.es.js.map +1 -1
- package/dist/domains/dashboards/components/dashboard-renderer.cjs.js +4 -3
- package/dist/domains/dashboards/components/dashboard-renderer.cjs.js.map +1 -1
- package/dist/domains/dashboards/components/dashboard-renderer.es.js +4 -3
- package/dist/domains/dashboards/components/dashboard-renderer.es.js.map +1 -1
- package/dist/domains/dashboards/components/widget-chrome.cjs.js +1 -1
- package/dist/domains/dashboards/components/widget-chrome.es.js +1 -1
- package/dist/domains/dashboards/components/widget-error.cjs.js +1 -1
- package/dist/domains/dashboards/components/widget-error.es.js +1 -1
- package/dist/domains/dashboards/hooks/use-widget-views.cjs.js +4 -3
- package/dist/domains/dashboards/hooks/use-widget-views.cjs.js.map +1 -1
- package/dist/domains/dashboards/hooks/use-widget-views.es.js +4 -3
- package/dist/domains/dashboards/hooks/use-widget-views.es.js.map +1 -1
- package/dist/domains/dashboards/kinds/scores/scores-widget.cjs.js +9 -6
- package/dist/domains/dashboards/kinds/scores/scores-widget.cjs.js.map +1 -1
- package/dist/domains/dashboards/kinds/scores/scores-widget.es.js +9 -6
- package/dist/domains/dashboards/kinds/scores/scores-widget.es.js.map +1 -1
- package/dist/domains/dashboards/kinds/table/table-tabs.cjs.js +2 -2
- package/dist/domains/dashboards/kinds/table/table-tabs.es.js +2 -2
- package/dist/domains/dashboards/kinds/table/table-widget.cjs.js +1 -1
- package/dist/domains/dashboards/kinds/table/table-widget.es.js +1 -1
- package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.cjs.js +6 -5
- package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.cjs.js.map +1 -1
- package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.es.js +6 -5
- package/dist/domains/dashboards/kinds/timeseries/timeseries-widget.es.js.map +1 -1
- package/dist/domains/dashboards/lib/chrome.cjs.js +9 -2
- package/dist/domains/dashboards/lib/chrome.cjs.js.map +1 -1
- package/dist/domains/dashboards/lib/chrome.es.js +9 -2
- package/dist/domains/dashboards/lib/chrome.es.js.map +1 -1
- package/dist/domains/dashboards/widget-kind.cjs.js.map +1 -1
- package/dist/domains/dashboards/widget-kind.es.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageCard.cjs.js +48 -0
- package/dist/domains/knowledge/components/KnowledgePageCard.cjs.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageCard.d.ts +1 -0
- package/dist/domains/knowledge/components/KnowledgePageCard.es.js +47 -0
- package/dist/domains/knowledge/components/KnowledgePageCard.es.js.map +1 -0
- package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js +63 -5
- package/dist/domains/knowledge/components/KnowledgePageDetail.cjs.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageDetail.es.js +64 -6
- package/dist/domains/knowledge/components/KnowledgePageDetail.es.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js +485 -47
- package/dist/domains/knowledge/components/KnowledgePageExplorer.cjs.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js +487 -50
- package/dist/domains/knowledge/components/KnowledgePageExplorer.es.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js +1051 -123
- package/dist/domains/knowledge/components/KnowledgePageGraph.cjs.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageGraph.es.js +1054 -126
- package/dist/domains/knowledge/components/KnowledgePageGraph.es.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js +75 -3
- package/dist/domains/knowledge/components/KnowledgePageTree.cjs.js.map +1 -1
- package/dist/domains/knowledge/components/KnowledgePageTree.es.js +76 -4
- package/dist/domains/knowledge/components/KnowledgePageTree.es.js.map +1 -1
- package/dist/domains/knowledge/lib/circleText.cjs.js +9 -0
- package/dist/domains/knowledge/lib/circleText.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/circleText.d.ts +1 -0
- package/dist/domains/knowledge/lib/circleText.es.js +8 -0
- package/dist/domains/knowledge/lib/circleText.es.js.map +1 -0
- package/dist/domains/knowledge/lib/fitViewport.cjs.js +82 -0
- package/dist/domains/knowledge/lib/fitViewport.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/fitViewport.d.ts +1 -0
- package/dist/domains/knowledge/lib/fitViewport.es.js +73 -0
- package/dist/domains/knowledge/lib/fitViewport.es.js.map +1 -0
- package/dist/domains/knowledge/lib/graphShape.cjs.js +524 -0
- package/dist/domains/knowledge/lib/graphShape.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/graphShape.d.ts +1 -0
- package/dist/domains/knowledge/lib/graphShape.es.js +499 -0
- package/dist/domains/knowledge/lib/graphShape.es.js.map +1 -0
- package/dist/domains/knowledge/lib/linkCountsText.cjs.js +11 -0
- package/dist/domains/knowledge/lib/linkCountsText.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/linkCountsText.d.ts +1 -0
- package/dist/domains/knowledge/lib/linkCountsText.es.js +10 -0
- package/dist/domains/knowledge/lib/linkCountsText.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageAddress.cjs.js +29 -0
- package/dist/domains/knowledge/lib/pageAddress.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/pageAddress.d.ts +1 -0
- package/dist/domains/knowledge/lib/pageAddress.es.js +27 -0
- package/dist/domains/knowledge/lib/pageAddress.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageGraph.cjs.js +11 -11
- package/dist/domains/knowledge/lib/pageGraph.cjs.js.map +1 -1
- package/dist/domains/knowledge/lib/pageGraph.es.js +11 -11
- package/dist/domains/knowledge/lib/pageGraph.es.js.map +1 -1
- package/dist/domains/knowledge/lib/pageRefs.cjs.js +69 -0
- package/dist/domains/knowledge/lib/pageRefs.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/pageRefs.d.ts +1 -0
- package/dist/domains/knowledge/lib/pageRefs.es.js +66 -0
- package/dist/domains/knowledge/lib/pageRefs.es.js.map +1 -0
- package/dist/domains/knowledge/lib/pageTree.cjs.js +5 -0
- package/dist/domains/knowledge/lib/pageTree.cjs.js.map +1 -1
- package/dist/domains/knowledge/lib/pageTree.es.js +5 -1
- package/dist/domains/knowledge/lib/pageTree.es.js.map +1 -1
- package/dist/domains/knowledge/lib/remarkKnowledgeLinks.cjs.js +82 -0
- package/dist/domains/knowledge/lib/remarkKnowledgeLinks.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/remarkKnowledgeLinks.d.ts +1 -0
- package/dist/domains/knowledge/lib/remarkKnowledgeLinks.es.js +78 -0
- package/dist/domains/knowledge/lib/remarkKnowledgeLinks.es.js.map +1 -0
- package/dist/domains/knowledge/lib/tooltipSide.cjs.js +77 -0
- package/dist/domains/knowledge/lib/tooltipSide.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/tooltipSide.d.ts +1 -0
- package/dist/domains/knowledge/lib/tooltipSide.es.js +75 -0
- package/dist/domains/knowledge/lib/tooltipSide.es.js.map +1 -0
- package/dist/domains/knowledge/lib/useLeavingNodes.cjs.js +65 -0
- package/dist/domains/knowledge/lib/useLeavingNodes.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/useLeavingNodes.d.ts +1 -0
- package/dist/domains/knowledge/lib/useLeavingNodes.es.js +62 -0
- package/dist/domains/knowledge/lib/useLeavingNodes.es.js.map +1 -0
- package/dist/domains/knowledge/lib/useStableWhile.cjs.js +15 -0
- package/dist/domains/knowledge/lib/useStableWhile.cjs.js.map +1 -0
- package/dist/domains/knowledge/lib/useStableWhile.d.ts +1 -0
- package/dist/domains/knowledge/lib/useStableWhile.es.js +14 -0
- package/dist/domains/knowledge/lib/useStableWhile.es.js.map +1 -0
- package/dist/domains/metrics/components/agent-runs-card.cjs.js +3 -3
- package/dist/domains/metrics/components/agent-runs-card.es.js +3 -3
- package/dist/domains/metrics/components/breakdown/breakdown-tab-body.cjs.js +1 -1
- package/dist/domains/metrics/components/breakdown/breakdown-tab-body.es.js +1 -1
- package/dist/domains/metrics/components/breakdown-card.cjs.js +1 -1
- package/dist/domains/metrics/components/breakdown-card.es.js +1 -1
- package/dist/domains/metrics/components/chart-area.cjs.js +1 -1
- package/dist/domains/metrics/components/chart-area.es.js +1 -1
- package/dist/domains/metrics/components/chart-card-error.cjs.js +1 -1
- package/dist/domains/metrics/components/chart-card-error.es.js +1 -1
- package/dist/domains/metrics/components/chart-card.cjs.js +1 -1
- package/dist/domains/metrics/components/chart-card.es.js +1 -1
- package/dist/domains/metrics/components/date-range-selector.cjs.js +1 -1
- package/dist/domains/metrics/components/date-range-selector.es.js +1 -1
- package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.cjs.js +3 -2
- package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.cjs.js.map +1 -1
- package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.es.js +3 -2
- package/dist/domains/metrics/components/distinct-ids/distinct-ids-chart.es.js.map +1 -1
- package/dist/domains/metrics/components/failure-rate-card.cjs.js +3 -2
- package/dist/domains/metrics/components/failure-rate-card.cjs.js.map +1 -1
- package/dist/domains/metrics/components/failure-rate-card.es.js +3 -2
- package/dist/domains/metrics/components/failure-rate-card.es.js.map +1 -1
- package/dist/domains/metrics/components/latency-card.cjs.js +3 -2
- package/dist/domains/metrics/components/latency-card.cjs.js.map +1 -1
- package/dist/domains/metrics/components/latency-card.es.js +3 -2
- package/dist/domains/metrics/components/latency-card.es.js.map +1 -1
- package/dist/domains/metrics/components/metrics-time-range-chip.cjs.js +1 -1
- package/dist/domains/metrics/components/metrics-time-range-chip.es.js +1 -1
- package/dist/domains/metrics/components/scores-card.cjs.js +2 -1
- package/dist/domains/metrics/components/scores-card.cjs.js.map +1 -1
- package/dist/domains/metrics/components/scores-card.es.js +2 -1
- package/dist/domains/metrics/components/scores-card.es.js.map +1 -1
- package/dist/domains/metrics/components/token-usage-card.cjs.js +3 -3
- package/dist/domains/metrics/components/token-usage-card.es.js +3 -3
- package/dist/domains/metrics/components/trace-aggregate-card.cjs.js +1 -1
- package/dist/domains/metrics/components/trace-aggregate-card.es.js +1 -1
- package/dist/domains/observability/components/observability-histogram.cjs.js +1 -1
- package/dist/domains/observability/components/observability-histogram.es.js +1 -1
- package/dist/domains/scores/components/trace-scores-list.cjs.js +2 -2
- package/dist/domains/scores/components/trace-scores-list.es.js +2 -2
- package/dist/domains/skills/skill-simple-form.cjs.js +1 -1
- package/dist/domains/skills/skill-simple-form.es.js +1 -1
- package/dist/domains/spans/components/spans-filter-bar.cjs.js +2 -2
- package/dist/domains/spans/components/spans-filter-bar.es.js +2 -2
- package/dist/domains/spans/hooks/use-spans-filter-bar.cjs.js +1 -1
- package/dist/domains/spans/hooks/use-spans-filter-bar.es.js +1 -1
- package/dist/domains/threads/components/threads-filter-bar.cjs.js +2 -2
- package/dist/domains/threads/components/threads-filter-bar.es.js +2 -2
- package/dist/domains/threads/hooks/use-threads-filter-bar.cjs.js +1 -1
- package/dist/domains/threads/hooks/use-threads-filter-bar.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 +2 -2
- package/dist/domains/traces/components/span-payload/span-output-renderers.es.js +2 -2
- package/dist/domains/traces/components/span-payload/span-payload-messages.cjs.js +2 -2
- package/dist/domains/traces/components/span-payload/span-payload-messages.es.js +2 -2
- 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/span-timeline-row.cjs.js +1 -1
- package/dist/domains/traces/components/span-timeline-row.es.js +1 -1
- package/dist/domains/traces/components/span-timing-hover-card.cjs.js +1 -1
- package/dist/domains/traces/components/span-timing-hover-card.es.js +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js +8 -2
- package/dist/domains/traces/components/trace-data-panel-view.cjs.js.map +1 -1
- package/dist/domains/traces/components/trace-data-panel-view.es.js +8 -2
- package/dist/domains/traces/components/trace-data-panel-view.es.js.map +1 -1
- package/dist/domains/traces/components/trace-error-cell.cjs.js +1 -1
- package/dist/domains/traces/components/trace-error-cell.es.js +1 -1
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.cjs.js +2 -2
- package/dist/domains/traces/components/traces-explorer/traces-explorer-filter-bar.es.js +2 -2
- package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.cjs.js +1 -1
- package/dist/domains/traces/components/traces-explorer/use-traces-filter-bar.es.js +1 -1
- package/dist/domains/workflows/runs/workflow-run-list.cjs.js +1 -1
- package/dist/domains/workflows/runs/workflow-run-list.es.js +1 -1
- package/dist/domains/workflows/workflow/input/workflow-processor-input.cjs.js +2 -2
- package/dist/domains/workflows/workflow/input/workflow-processor-input.es.js +2 -2
- package/dist/domains/workflows/workflow/use-workflow-trigger.cjs.js +3 -3
- package/dist/domains/workflows/workflow/use-workflow-trigger.es.js +3 -3
- package/dist/domains/workflows/workflow/workflow-input-data.cjs.js +1 -1
- package/dist/domains/workflows/workflow/workflow-input-data.es.js +1 -1
- package/dist/domains/workflows/workflow/workflow-suspended-steps.cjs.js +2 -2
- package/dist/domains/workflows/workflow/workflow-suspended-steps.es.js +2 -2
- package/dist/domains/workflows/workflow/workflow-time-travel-form.cjs.js +2 -2
- package/dist/domains/workflows/workflow/workflow-time-travel-form.es.js +2 -2
- package/dist/domains/workspace/components/workspace-add-skill-dialog.cjs.js +1 -1
- package/dist/domains/workspace/components/workspace-add-skill-dialog.es.js +1 -1
- package/dist/domains/workspace/components/workspace-markdown-preview.cjs.js +1 -1
- package/dist/domains/workspace/components/workspace-markdown-preview.es.js +1 -1
- package/dist/{filter-bar-time-range-mg9JeYue.js → filter-bar-time-range-qlV8p7hp.js} +2 -2
- package/dist/{filter-bar-time-range-mg9JeYue.js.map → filter-bar-time-range-qlV8p7hp.js.map} +1 -1
- package/dist/{filter-bar-time-range-BA-pXMlo.cjs → filter-bar-time-range-zdM024JD.cjs} +2 -2
- package/dist/{filter-bar-time-range-BA-pXMlo.cjs.map → filter-bar-time-range-zdM024JD.cjs.map} +1 -1
- package/dist/lib/form/dynamic-form.cjs.js +2 -2
- package/dist/lib/form/dynamic-form.es.js +2 -2
- 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.cjs.js +1 -1
- package/dist/lib/form/zod-provider.es.js +1 -1
- package/dist/{span-payload-primitives-B3RdahsC.js → span-payload-primitives-CKKIAVPJ.js} +4 -4
- package/dist/{span-payload-primitives-B3RdahsC.js.map → span-payload-primitives-CKKIAVPJ.js.map} +1 -1
- package/dist/{span-payload-primitives-_2d-pAOD.cjs → span-payload-primitives-D4tHWN2W.cjs} +4 -4
- package/dist/{span-payload-primitives-_2d-pAOD.cjs.map → span-payload-primitives-D4tHWN2W.cjs.map} +1 -1
- package/dist/src/domains/chat/knowledge/knowledge-links.d.ts +32 -4
- package/dist/src/domains/chat/knowledge/pinned-knowledge-data.d.ts +2 -0
- package/dist/src/domains/chat/tools/badges/knowledge-body-range.d.ts +12 -0
- package/dist/src/domains/chat/tools/badges/knowledge-tool-badge.d.ts +5 -2
- package/dist/src/domains/chat/tools/badges/mcp-input-request-badge.d.ts +18 -0
- package/dist/src/domains/chat/tools/badges/tool-badge.d.ts +4 -1
- package/dist/src/domains/chat/tools/badges/use-deferred-input-request.d.ts +44 -0
- package/dist/src/domains/chat/tools/badges/use-mcp-task-progress.d.ts +6 -1
- package/dist/src/domains/chat/tools/connect-prompt-tool.d.ts +10 -1
- package/dist/src/domains/chat/tools/mcp-input-request-tool.d.ts +18 -0
- package/dist/src/domains/chat/tools/mcp-input-request.d.ts +40 -0
- package/dist/src/domains/chat/tools/tool-card-kind.d.ts +4 -2
- package/dist/src/domains/chat/tools/tool-card.d.ts +1 -1
- package/dist/src/domains/connect/types.d.ts +16 -0
- package/dist/src/domains/dashboards/components/dashboard-renderer.d.ts +4 -2
- package/dist/src/domains/dashboards/hooks/use-widget-views.d.ts +4 -3
- package/dist/src/domains/dashboards/index.d.ts +1 -1
- package/dist/src/domains/dashboards/kinds/scores/scores-widget.d.ts +1 -1
- package/dist/src/domains/dashboards/lib/chrome.d.ts +6 -4
- package/dist/src/domains/dashboards/widget-kind.d.ts +12 -0
- package/dist/src/domains/knowledge/components/KnowledgePageCard.d.ts +23 -0
- package/dist/src/domains/knowledge/components/KnowledgePageExplorer.d.ts +29 -0
- package/dist/src/domains/knowledge/components/KnowledgePageGraph.d.ts +27 -1
- package/dist/src/domains/knowledge/components/KnowledgePageTree.d.ts +2 -1
- package/dist/src/domains/knowledge/lib/circleText.d.ts +2 -0
- package/dist/src/domains/knowledge/lib/fitViewport.d.ts +67 -0
- package/dist/src/domains/knowledge/lib/graphShape.d.ts +131 -0
- package/dist/src/domains/knowledge/lib/linkCountsText.d.ts +5 -0
- package/dist/src/domains/knowledge/lib/pageAddress.d.ts +5 -0
- package/dist/src/domains/knowledge/lib/pageGraph.d.ts +4 -4
- package/dist/src/domains/knowledge/lib/pageRefs.d.ts +15 -0
- package/dist/src/domains/knowledge/lib/pageTree.d.ts +2 -0
- package/dist/src/domains/knowledge/lib/remarkKnowledgeLinks.d.ts +13 -0
- package/dist/src/domains/knowledge/lib/tooltipSide.d.ts +40 -0
- package/dist/src/domains/knowledge/lib/useLeavingNodes.d.ts +14 -0
- package/dist/src/domains/knowledge/lib/useStableWhile.d.ts +5 -0
- package/dist/src/domains/knowledge/pageTypes.d.ts +6 -1
- package/dist/src/ds/components/DateTimeRangePicker/date-time-range-picker.d.ts +12 -1
- package/dist/src/ds/components/MarkdownRenderer/markdown-renderer.d.ts +8 -1
- package/dist/src/ds/components/MetricsCard/metrics-card-headline.d.ts +1 -1
- package/dist/src/ds/components/MetricsLineChart/metrics-line-chart.d.ts +8 -0
- package/dist/src/ds/components/ai/tool-call/tool-phrases.d.ts +6 -0
- package/dist/style.css +73 -2
- package/dist/{tool-approval-1qiB4hhG.cjs → tool-approval-CJvPDL7D.cjs} +4 -4
- package/dist/{tool-approval-1qiB4hhG.cjs.map → tool-approval-CJvPDL7D.cjs.map} +1 -1
- package/dist/{tool-approval-B6MFcaKV.js → tool-approval-DyN11vFA.js} +4 -4
- package/dist/{tool-approval-B6MFcaKV.js.map → tool-approval-DyN11vFA.js.map} +1 -1
- package/dist/{tool-call-Bu66PkD-.cjs → tool-call-DBn14X-3.cjs} +9 -3
- package/dist/{tool-call-Bu66PkD-.cjs.map → tool-call-DBn14X-3.cjs.map} +1 -1
- package/dist/{tool-call-Ch9-jjXU.js → tool-call-Dsj43lvJ.js} +9 -3
- package/dist/{tool-call-Ch9-jjXU.js.map → tool-call-Dsj43lvJ.js.map} +1 -1
- package/dist/{tool-card-DrqPZfPQ.cjs → tool-card-BOLXeKIp.cjs} +167 -126
- package/dist/tool-card-BOLXeKIp.cjs.map +1 -0
- package/dist/{tool-card-sO6P2Qj4.js → tool-card-HZ5bm7ue.js} +168 -127
- package/dist/tool-card-HZ5bm7ue.js.map +1 -0
- package/dist/{tool-presentation-DvCsb_kz.js → tool-presentation-CvibOP1J.js} +6 -1
- package/dist/tool-presentation-CvibOP1J.js.map +1 -0
- package/dist/{tool-presentation-CQlDEwgS.cjs → tool-presentation-D6nzVruN.cjs} +6 -1
- package/dist/tool-presentation-D6nzVruN.cjs.map +1 -0
- package/package.json +11 -11
- package/dist/MarkdownRenderer-2GOXQJEv.js.map +0 -1
- package/dist/MarkdownRenderer-CB8Z_CHc.cjs.map +0 -1
- package/dist/MetricsCard-CEB-f2sv.cjs.map +0 -1
- package/dist/MetricsCard-M8awJ2B_.js.map +0 -1
- package/dist/MetricsLineChart-BhHoduO0.js.map +0 -1
- package/dist/MetricsLineChart-CjBm4IXu.cjs.map +0 -1
- package/dist/date-time-range-picker-CTt7Od0P.cjs.map +0 -1
- package/dist/date-time-range-picker-DKh1K9Iy.js.map +0 -1
- package/dist/domains/knowledge/lib/pageLayout.cjs.js +0 -49
- package/dist/domains/knowledge/lib/pageLayout.cjs.js.map +0 -1
- package/dist/domains/knowledge/lib/pageLayout.d.ts +0 -1
- package/dist/domains/knowledge/lib/pageLayout.es.js +0 -48
- package/dist/domains/knowledge/lib/pageLayout.es.js.map +0 -1
- package/dist/src/domains/knowledge/lib/pageLayout.d.ts +0 -24
- package/dist/tool-card-DrqPZfPQ.cjs.map +0 -1
- package/dist/tool-card-sO6P2Qj4.js.map +0 -1
- package/dist/tool-presentation-CQlDEwgS.cjs.map +0 -1
- package/dist/tool-presentation-DvCsb_kz.js.map +0 -1
|
@@ -0,0 +1,499 @@
|
|
|
1
|
+
import { comparePagePosition } from "./pageTree.es.js";
|
|
2
|
+
// src/domains/knowledge/lib/graphShape.ts
|
|
3
|
+
/** Most scopes and ancestors beyond the first ring that draw as circles; any more fall back to dots. */
|
|
4
|
+
var HIGHER_LEVEL_CAP = 10;
|
|
5
|
+
/** Pages at most this many parent links from the focus draw as full circles. */
|
|
6
|
+
var FULL_CIRCLE_DEPTH = 1;
|
|
7
|
+
/**
|
|
8
|
+
* How many pages one level farther out than the usual circles still draw as circles, so a page with no
|
|
9
|
+
* children reads like a focused scope instead of a ring of bare dots. The rest of that level, and the level
|
|
10
|
+
* below, are dots.
|
|
11
|
+
*/
|
|
12
|
+
var ROOT_CIRCLE_CAP = 8;
|
|
13
|
+
/**
|
|
14
|
+
* The pages promoted to circles at depth two: for a centre with no children, its first siblings, the children
|
|
15
|
+
* of its parent, since those are the pages around it. A centre with children needs no promotion: its own
|
|
16
|
+
* children are the circles.
|
|
17
|
+
*/
|
|
18
|
+
function promotedCircles(children, center) {
|
|
19
|
+
const promoted = /* @__PURE__ */ new Set();
|
|
20
|
+
if (center && !(children.get(center.id)?.length ?? 0) && !(center.childCount ?? 0)) {
|
|
21
|
+
if (center.parentId && center.parentId !== center.id) (children.get(center.parentId) ?? []).filter((child) => child.id !== center.id && !isChildPlaceholder(child)).slice(0, 8).forEach((child) => promoted.add(child.id));
|
|
22
|
+
}
|
|
23
|
+
return promoted;
|
|
24
|
+
}
|
|
25
|
+
/** A dot's diameter. */
|
|
26
|
+
var KNOWLEDGE_DOT_SIZE = 20;
|
|
27
|
+
/** A dot's diameter when it carries its link count. */
|
|
28
|
+
var KNOWLEDGE_COUNTED_DOT_SIZE = 28;
|
|
29
|
+
/** How far past its edge a dot still counts as under the pointer. */
|
|
30
|
+
var KNOWLEDGE_DOT_HIT_MARGIN = 8;
|
|
31
|
+
var PLACEHOLDER_PREFIX = "more:";
|
|
32
|
+
var REST_PREFIX = "rest:";
|
|
33
|
+
var GROUP_PREFIX = "group:";
|
|
34
|
+
/** A stand-in dot for a child that hasn't loaded yet; `parentId` is the page whose children it stands for. */
|
|
35
|
+
function isChildPlaceholder(page) {
|
|
36
|
+
return page.id.startsWith(PLACEHOLDER_PREFIX);
|
|
37
|
+
}
|
|
38
|
+
/** The circle that says how many more children the centre has than are drawn; it opens nothing. */
|
|
39
|
+
function isRestCircle(page) {
|
|
40
|
+
return page.id.startsWith(REST_PREFIX);
|
|
41
|
+
}
|
|
42
|
+
/** One circle standing for several sibling scopes of one type, e.g. a resource's memory threads. */
|
|
43
|
+
function isScopeGroup(page) {
|
|
44
|
+
return page.id.startsWith(GROUP_PREFIX);
|
|
45
|
+
}
|
|
46
|
+
function liveOnly(pages) {
|
|
47
|
+
return pages.filter((page) => !page.deletedAt && !page.mergedInto);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Walks parent links out from `focusId` (or, with no focus, from the roots), so each page's depth is how
|
|
51
|
+
* many links it sits from the focus, whichever way they run: the focus's parent and its children are 1,
|
|
52
|
+
* its siblings and grandchildren 2. The focus and pages within {@link FULL_CIRCLE_DEPTH} are full circles;
|
|
53
|
+
* every other page, every page the walk never reaches, and every placeholder is a dot. With no focus the
|
|
54
|
+
* first root becomes the centre and the other roots sit one link from it. A root is any page whose parent is not loaded, so a page cut off from its parent by a bounded graph is a root too.
|
|
55
|
+
*/
|
|
56
|
+
function graphShape(pages, focusId, linkEnds = noPages) {
|
|
57
|
+
const live = liveOnly(pages);
|
|
58
|
+
const byId = new Map(live.map((page) => [page.id, page]));
|
|
59
|
+
const children = /* @__PURE__ */ new Map();
|
|
60
|
+
const roots = [];
|
|
61
|
+
for (const page of live) {
|
|
62
|
+
const parent = page.parentId && page.parentId !== page.id ? byId.get(page.parentId) : void 0;
|
|
63
|
+
if (!parent) roots.push(page);
|
|
64
|
+
else children.set(parent.id, [...children.get(parent.id) ?? [], page]);
|
|
65
|
+
}
|
|
66
|
+
for (const list of children.values()) list.sort(comparePagePosition);
|
|
67
|
+
roots.sort(comparePagePosition);
|
|
68
|
+
const center = focusId && byId.has(focusId) ? focusId : roots[0]?.id ?? null;
|
|
69
|
+
const centerPage = center ? byId.get(center) : void 0;
|
|
70
|
+
const depth = /* @__PURE__ */ new Map();
|
|
71
|
+
const branch = /* @__PURE__ */ new Map();
|
|
72
|
+
const via = /* @__PURE__ */ new Map();
|
|
73
|
+
const queue = [];
|
|
74
|
+
const visit = (id, from, at, fromBranch) => {
|
|
75
|
+
if (depth.has(id)) return;
|
|
76
|
+
depth.set(id, at);
|
|
77
|
+
via.set(id, from);
|
|
78
|
+
const own = at === 1 ? id : fromBranch;
|
|
79
|
+
if (own) branch.set(id, own);
|
|
80
|
+
queue.push(id);
|
|
81
|
+
};
|
|
82
|
+
if (center) visit(center, null, 0, void 0);
|
|
83
|
+
else for (const root of roots) visit(root.id, null, 1, void 0);
|
|
84
|
+
while (queue.length) {
|
|
85
|
+
const id = queue.shift();
|
|
86
|
+
const at = depth.get(id);
|
|
87
|
+
const page = byId.get(id);
|
|
88
|
+
const parentId = page?.parentId && byId.has(page.parentId) ? page.parentId : null;
|
|
89
|
+
if (parentId) visit(parentId, id, at + 1, branch.get(id));
|
|
90
|
+
for (const child of children.get(id) ?? []) visit(child.id, id, at + 1, branch.get(id));
|
|
91
|
+
if (id === center && centerPage && roots.includes(centerPage)) {
|
|
92
|
+
for (const root of roots) if (root.id !== center) visit(root.id, id, at + 1, root.id);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
const level = /* @__PURE__ */ new Map();
|
|
96
|
+
for (let up = focusId ? byId.get(focusId)?.parentId : void 0; up && !level.has(up);) {
|
|
97
|
+
const above = byId.get(up);
|
|
98
|
+
if (!above) break;
|
|
99
|
+
level.set(above.id, above.isScope ? "scope" : "ancestor");
|
|
100
|
+
up = above.parentId && above.parentId !== above.id ? above.parentId : void 0;
|
|
101
|
+
}
|
|
102
|
+
for (const page of live) if (page.isScope && !isScopeGroup(page) && !isChildPlaceholder(page) && depth.has(page.id)) level.set(page.id, "scope");
|
|
103
|
+
const rootCircles = promotedCircles(children, centerPage);
|
|
104
|
+
const form = /* @__PURE__ */ new Map();
|
|
105
|
+
const linked = /* @__PURE__ */ new Set();
|
|
106
|
+
let farCircles = 0;
|
|
107
|
+
for (const page of live) {
|
|
108
|
+
const at = depth.get(page.id);
|
|
109
|
+
const near = at !== void 0 && (at <= 1 || rootCircles.has(page.id)) && !isChildPlaceholder(page);
|
|
110
|
+
const higher = at !== void 0 && level.has(page.id) && !isChildPlaceholder(page);
|
|
111
|
+
const linkedEnd = at === void 0 && linkEnds.has(page.id) && !isChildPlaceholder(page);
|
|
112
|
+
if (linkedEnd) linked.add(page.id);
|
|
113
|
+
form.set(page.id, near || linkedEnd || higher && farCircles++ < 10 ? "full" : "dot");
|
|
114
|
+
}
|
|
115
|
+
return {
|
|
116
|
+
depth,
|
|
117
|
+
form,
|
|
118
|
+
branch,
|
|
119
|
+
via,
|
|
120
|
+
level,
|
|
121
|
+
linked,
|
|
122
|
+
center
|
|
123
|
+
};
|
|
124
|
+
}
|
|
125
|
+
/** Radius of the first ring: at least this, more when its full circles need the room. */
|
|
126
|
+
var FIRST_RING = 230;
|
|
127
|
+
/** Widest the first ring of full circles grows before they stagger over more rows. */
|
|
128
|
+
var MAX_CIRCLE_RING = 300;
|
|
129
|
+
/** Gap from the full-circle ring out to the first ring of dots. */
|
|
130
|
+
var FIRST_DOT_RING_GAP = 150;
|
|
131
|
+
/** Gap between rings of dots. */
|
|
132
|
+
var DOT_RING_GAP = 70;
|
|
133
|
+
/** Space a dot needs along its ring before the next one staggers outward. */
|
|
134
|
+
var DOT_SPACING = 28;
|
|
135
|
+
/** Space kept clear between the focus, its link-end circles and the first ring around them. */
|
|
136
|
+
var LINK_GAP = 16;
|
|
137
|
+
var noPages = /* @__PURE__ */ new Set();
|
|
138
|
+
/**
|
|
139
|
+
* Places the focus's link-end circles on rings around it, inside the first ring. Each circle keeps clear of
|
|
140
|
+
* the focus, of the line from the focus to every page on the first ring (its parent and children) and of
|
|
141
|
+
* its neighbours, so the angles those lines run at are skipped and the circles fill the gaps between them;
|
|
142
|
+
* when the gaps on a ring are full the rest stack onto a ring outside it. `reach` is how far out the
|
|
143
|
+
* outermost circle's edge sits.
|
|
144
|
+
*/
|
|
145
|
+
function layoutLinkEnds(ends, center, positions, firstRing, sizeOf) {
|
|
146
|
+
const half = Math.max(...ends.map((page) => sizeOf(page))) / 2;
|
|
147
|
+
const blocked = firstRing.flatMap((id) => {
|
|
148
|
+
const at = positions.get(id);
|
|
149
|
+
return at ? [Math.atan2(at.y, at.x)] : [];
|
|
150
|
+
});
|
|
151
|
+
const points = /* @__PURE__ */ new Map();
|
|
152
|
+
let remaining = [...ends];
|
|
153
|
+
let radius = half * 2.5 + LINK_GAP;
|
|
154
|
+
let reach = radius + half;
|
|
155
|
+
for (let rows = 0; remaining.length && rows < 12; rows++) {
|
|
156
|
+
const margin = Math.asin(Math.min(1, (half + LINK_GAP / 2) / radius));
|
|
157
|
+
const step = 2 * Math.asin(Math.min(1, (half * 2 + LINK_GAP) / (2 * radius)));
|
|
158
|
+
const gaps = blocked.length ? [...blocked].sort((a, b) => a - b) : [-Math.PI];
|
|
159
|
+
const slots = [];
|
|
160
|
+
gaps.forEach((from, index) => {
|
|
161
|
+
const next = gaps[(index + 1) % gaps.length];
|
|
162
|
+
const start = from + margin;
|
|
163
|
+
const end = (index + 1 < gaps.length ? next : next + 2 * Math.PI) - margin;
|
|
164
|
+
for (let angle = start; angle <= end + 1e-9; angle += step) slots.push(angle);
|
|
165
|
+
});
|
|
166
|
+
remaining.splice(0, Math.max(1, slots.length)).forEach((page, index) => {
|
|
167
|
+
const angle = slots[index] ?? slots[0] ?? 0;
|
|
168
|
+
points.set(page.id, {
|
|
169
|
+
x: Math.cos(angle) * radius,
|
|
170
|
+
y: Math.sin(angle) * radius
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
reach = radius + half;
|
|
174
|
+
radius += half * 2 + LINK_GAP;
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
points,
|
|
178
|
+
reach
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
/**
|
|
182
|
+
* Places the focus at the centre and every other page on the ring for its depth, each page's children in
|
|
183
|
+
* a slice of the circle taken out of its parent's slice, sized by how much hangs under each one (a full
|
|
184
|
+
* circle counts for more than a dot). The focus's parent gets the slice at the top. Dots that don't fit
|
|
185
|
+
* along their ring stagger outward in rows. Pages the walk never reached go on one outer ring, except
|
|
186
|
+
* those in `near` (the focus's links), which sit on a ring close around the focus so they stay in view.
|
|
187
|
+
*/
|
|
188
|
+
function radialLayout(pages, shape, sizeOf, near = noPages) {
|
|
189
|
+
const live = liveOnly(pages);
|
|
190
|
+
const byId = new Map(live.map((page) => [page.id, page]));
|
|
191
|
+
const kids = /* @__PURE__ */ new Map();
|
|
192
|
+
for (const id of shape.depth.keys()) {
|
|
193
|
+
if (!byId.has(id) || id === shape.center) continue;
|
|
194
|
+
const from = shape.via.get(id) ?? null;
|
|
195
|
+
kids.set(from, [...kids.get(from) ?? [], id]);
|
|
196
|
+
}
|
|
197
|
+
const weight = /* @__PURE__ */ new Map();
|
|
198
|
+
const weigh = (id) => {
|
|
199
|
+
const own = shape.form.get(id) === "full" ? 4 : 1;
|
|
200
|
+
const below = (kids.get(id) ?? []).reduce((sum, kid) => sum + weigh(kid), 0);
|
|
201
|
+
const total = Math.max(own, below);
|
|
202
|
+
weight.set(id, total);
|
|
203
|
+
return total;
|
|
204
|
+
};
|
|
205
|
+
const firstRing = shape.center ? kids.get(shape.center) ?? [] : kids.get(null) ?? [];
|
|
206
|
+
firstRing.forEach(weigh);
|
|
207
|
+
const circleWidth = /* @__PURE__ */ new Map();
|
|
208
|
+
for (const [id, at] of shape.depth) {
|
|
209
|
+
const page = byId.get(id);
|
|
210
|
+
if (!page || id === shape.center || shape.form.get(id) !== "full") continue;
|
|
211
|
+
circleWidth.set(at, (circleWidth.get(at) ?? 0) + sizeOf(page) + 30);
|
|
212
|
+
}
|
|
213
|
+
const firstWidth = circleWidth.get(1) ?? 0;
|
|
214
|
+
const ringRows = Math.max(1, Math.ceil(firstWidth / (2 * Math.PI * MAX_CIRCLE_RING)));
|
|
215
|
+
const fullCount = [...shape.depth].filter(([id, at]) => at === 1 && id !== shape.center && shape.form.get(id) === "full" && byId.has(id)).length;
|
|
216
|
+
const rowStep = fullCount ? firstWidth / fullCount : 0;
|
|
217
|
+
const radii = [0, Math.max(FIRST_RING, firstWidth / ringRows / (2 * Math.PI))];
|
|
218
|
+
const radius = (at) => {
|
|
219
|
+
while (radii.length <= at) {
|
|
220
|
+
const next = radii.length;
|
|
221
|
+
const last = radii[next - 1];
|
|
222
|
+
const gap = circleWidth.has(next - 1) && next > 1 ? FIRST_DOT_RING_GAP : DOT_RING_GAP;
|
|
223
|
+
const outer = next === 2 ? (ringRows - 1) * rowStep : 0;
|
|
224
|
+
radii.push(Math.max(last + gap + outer, (circleWidth.get(next) ?? 0) / (2 * Math.PI)));
|
|
225
|
+
}
|
|
226
|
+
return radii[at];
|
|
227
|
+
};
|
|
228
|
+
let circleIndex = 0;
|
|
229
|
+
const positions = /* @__PURE__ */ new Map();
|
|
230
|
+
const place = (ids, at, start, span) => {
|
|
231
|
+
const total = ids.reduce((sum, id) => sum + (weight.get(id) ?? 1), 0) || 1;
|
|
232
|
+
const dots = ids.filter((id) => shape.form.get(id) !== "full").length;
|
|
233
|
+
const arc = span * radius(at);
|
|
234
|
+
const perRow = Math.max(1, Math.floor(arc / DOT_SPACING));
|
|
235
|
+
let angle = start;
|
|
236
|
+
let dotIndex = 0;
|
|
237
|
+
for (const id of ids) {
|
|
238
|
+
const share = (weight.get(id) ?? 1) / total * span;
|
|
239
|
+
const middle = angle + share / 2;
|
|
240
|
+
const full = shape.form.get(id) === "full";
|
|
241
|
+
const row = full || dots <= perRow ? 0 : dotIndex % Math.ceil(dots / perRow);
|
|
242
|
+
if (!full) dotIndex++;
|
|
243
|
+
const r = radius(at) + (full && at === 1 ? circleIndex++ % ringRows * rowStep : row * DOT_SPACING);
|
|
244
|
+
positions.set(id, {
|
|
245
|
+
x: Math.cos(middle) * r,
|
|
246
|
+
y: Math.sin(middle) * r
|
|
247
|
+
});
|
|
248
|
+
place(kids.get(id) ?? [], at + 1, angle, share);
|
|
249
|
+
angle += share;
|
|
250
|
+
}
|
|
251
|
+
};
|
|
252
|
+
const firstShare = firstRing.length ? (weight.get(firstRing[0]) ?? 1) / firstRing.reduce((s, id) => s + (weight.get(id) ?? 1), 0) * 2 * Math.PI : 0;
|
|
253
|
+
const run = () => {
|
|
254
|
+
positions.clear();
|
|
255
|
+
circleIndex = 0;
|
|
256
|
+
if (shape.center) positions.set(shape.center, {
|
|
257
|
+
x: 0,
|
|
258
|
+
y: 0
|
|
259
|
+
});
|
|
260
|
+
place(firstRing, 1, -Math.PI / 2 - firstShare / 2, 2 * Math.PI);
|
|
261
|
+
};
|
|
262
|
+
run();
|
|
263
|
+
const unreached = live.filter((page) => !positions.has(page.id)).sort((a, b) => a.id < b.id ? -1 : 1);
|
|
264
|
+
const close = unreached.filter((page) => near.has(page.id) && shape.form.get(page.id) === "full");
|
|
265
|
+
const linkDots = unreached.filter((page) => near.has(page.id) && shape.form.get(page.id) !== "full");
|
|
266
|
+
let linkRingReach = 0;
|
|
267
|
+
const parentId = shape.center ? byId.get(shape.center)?.parentId : void 0;
|
|
268
|
+
const hasChildren = firstRing.some((id) => id !== parentId);
|
|
269
|
+
if (close.length && shape.center && hasChildren) {
|
|
270
|
+
const half = Math.max(...close.map((page) => sizeOf(page))) / 2;
|
|
271
|
+
let extent = 0;
|
|
272
|
+
for (const [id, point] of positions) {
|
|
273
|
+
const page = byId.get(id);
|
|
274
|
+
if (page) extent = Math.max(extent, Math.hypot(point.x, point.y) + sizeOf(page) / 2);
|
|
275
|
+
}
|
|
276
|
+
const ring = Math.max(extent + LINK_GAP + half, close.length * (half * 2 + LINK_GAP) / (2 * Math.PI));
|
|
277
|
+
close.forEach((page, index) => {
|
|
278
|
+
const angle = Math.PI / 2 + index / close.length * 2 * Math.PI;
|
|
279
|
+
positions.set(page.id, {
|
|
280
|
+
x: Math.cos(angle) * ring,
|
|
281
|
+
y: Math.sin(angle) * ring
|
|
282
|
+
});
|
|
283
|
+
});
|
|
284
|
+
linkRingReach = ring + half;
|
|
285
|
+
} else if (close.length && shape.center) {
|
|
286
|
+
const linked = layoutLinkEnds(close, shape.center, positions, firstRing, sizeOf);
|
|
287
|
+
const firstSize = Math.max(0, ...firstRing.filter((id) => shape.form.get(id) === "full").map((id) => sizeOf(byId.get(id))));
|
|
288
|
+
radii.length = 2;
|
|
289
|
+
radii[1] = Math.max(radii[1], linked.reach + LINK_GAP + firstSize / 2);
|
|
290
|
+
run();
|
|
291
|
+
const relinked = layoutLinkEnds(close, shape.center, positions, firstRing, sizeOf);
|
|
292
|
+
for (const [id, point] of relinked.points) positions.set(id, point);
|
|
293
|
+
}
|
|
294
|
+
const closeDots = linkDots;
|
|
295
|
+
const closeRing = Math.min(175, Math.max(120, closeDots.length * DOT_SPACING / (2 * Math.PI)));
|
|
296
|
+
closeDots.forEach((page, index) => {
|
|
297
|
+
const angle = Math.PI / 2 + index / closeDots.length * 2 * Math.PI;
|
|
298
|
+
positions.set(page.id, {
|
|
299
|
+
x: Math.cos(angle) * closeRing,
|
|
300
|
+
y: Math.sin(angle) * closeRing
|
|
301
|
+
});
|
|
302
|
+
});
|
|
303
|
+
const far = unreached.filter((page) => !near.has(page.id));
|
|
304
|
+
if (far.length) {
|
|
305
|
+
const outer = Math.max(radius(radii.length), linkRingReach) + DOT_RING_GAP;
|
|
306
|
+
far.forEach((page, index) => {
|
|
307
|
+
const angle = -Math.PI / 2 + index / far.length * 2 * Math.PI;
|
|
308
|
+
positions.set(page.id, {
|
|
309
|
+
x: Math.cos(angle) * outer,
|
|
310
|
+
y: Math.sin(angle) * outer
|
|
311
|
+
});
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
return positions;
|
|
315
|
+
}
|
|
316
|
+
/** Colours for the dots of each branch around the focus, in branch order. */
|
|
317
|
+
var BRANCH_COLORS = [
|
|
318
|
+
"var(--chart-blue)",
|
|
319
|
+
"var(--chart-green)",
|
|
320
|
+
"var(--chart-amber)",
|
|
321
|
+
"var(--chart-pink)",
|
|
322
|
+
"var(--chart-cyan)",
|
|
323
|
+
"var(--chart-orange)",
|
|
324
|
+
"var(--chart-purple)",
|
|
325
|
+
"var(--chart-red)"
|
|
326
|
+
];
|
|
327
|
+
/** One colour per branch, in the order the branches sit around the focus. */
|
|
328
|
+
function branchColors(pages, shape) {
|
|
329
|
+
const order = [];
|
|
330
|
+
for (const page of pages) {
|
|
331
|
+
const own = shape.branch.get(page.id);
|
|
332
|
+
if (own && !order.includes(own)) order.push(own);
|
|
333
|
+
}
|
|
334
|
+
return new Map(order.map((id, index) => [id, BRANCH_COLORS[index % BRANCH_COLORS.length]]));
|
|
335
|
+
}
|
|
336
|
+
/** Framing never zooms out past this, so circle names stay readable; a bigger graph is panned, not shrunk. */
|
|
337
|
+
var READABLE_MIN_ZOOM = .7;
|
|
338
|
+
/** Children a drawn page shows at most; the rest are counted, not drawn. */
|
|
339
|
+
var GRAPH_CHILD_CAP = 48;
|
|
340
|
+
/** How many more children a click on a "+N more" circle draws. */
|
|
341
|
+
var REST_BATCH = 12;
|
|
342
|
+
/** Stand-in dots drawn at most for a page whose children haven't loaded yet. */
|
|
343
|
+
var PLACEHOLDER_CAP = 8;
|
|
344
|
+
/** Most circles whose children are loaded just to draw them as dots around it. */
|
|
345
|
+
var WANTED_CIRCLE_CAP = 24;
|
|
346
|
+
/** Roots drawn beside the root at the centre when nothing is focused. */
|
|
347
|
+
var SIBLING_ROOT_CAP = 8;
|
|
348
|
+
/** Children around a page that fit at full size; past this the circles shrink to make room. */
|
|
349
|
+
var CROWD_START = 16;
|
|
350
|
+
/** Smallest a crowded ring's circles shrink to, as a fraction of their usual size. */
|
|
351
|
+
var CROWD_MIN_SCALE = .7;
|
|
352
|
+
/** How much to shrink each of `count` circles sharing a ring, so a page with dozens of children still fits. */
|
|
353
|
+
function crowdScale(count) {
|
|
354
|
+
if (count <= 16) return 1;
|
|
355
|
+
return Math.max(CROWD_MIN_SCALE, Math.sqrt(16 / count));
|
|
356
|
+
}
|
|
357
|
+
/** Sibling scopes of one type (e.g. `thread`) collapse into one circle from this many. */
|
|
358
|
+
var SCOPE_GROUP_MIN = 3;
|
|
359
|
+
var nobody = { author: "" };
|
|
360
|
+
function syntheticPage(id, parent, fields) {
|
|
361
|
+
return {
|
|
362
|
+
id,
|
|
363
|
+
scopeId: parent.scopeId,
|
|
364
|
+
parentId: parent.id,
|
|
365
|
+
isScope: false,
|
|
366
|
+
position: "",
|
|
367
|
+
name: "",
|
|
368
|
+
version: 0,
|
|
369
|
+
createdBy: nobody,
|
|
370
|
+
updatedBy: nobody,
|
|
371
|
+
createdAt: "",
|
|
372
|
+
updatedAt: "",
|
|
373
|
+
...fields
|
|
374
|
+
};
|
|
375
|
+
}
|
|
376
|
+
/** The type part of a scope address (`thread` in `thread:abc`), or `null` for a page or an untyped scope. */
|
|
377
|
+
function scopeType(page) {
|
|
378
|
+
if (!page.isScope || !page.address) return null;
|
|
379
|
+
const colon = page.address.indexOf(":");
|
|
380
|
+
return colon > 0 ? page.address.slice(0, colon) : null;
|
|
381
|
+
}
|
|
382
|
+
/**
|
|
383
|
+
* What a lazily loaded graph draws: the focus (or the root scopes), everything within two parent links
|
|
384
|
+
* of it, and the focus's path up to its root. A page's children are capped; sibling scopes of one type
|
|
385
|
+
* past {@link SCOPE_GROUP_MIN} collapse into one group circle unless opened (never under the focus
|
|
386
|
+
* itself); a full-circle page whose children haven't loaded gets stand-in dots, one per child up to
|
|
387
|
+
* {@link PLACEHOLDER_CAP}.
|
|
388
|
+
*/
|
|
389
|
+
function lazyGraph(input) {
|
|
390
|
+
const cap = input.cap ?? 48;
|
|
391
|
+
const live = liveOnly(input.pages);
|
|
392
|
+
const byId = new Map(live.map((page) => [page.id, page]));
|
|
393
|
+
const children = /* @__PURE__ */ new Map();
|
|
394
|
+
const roots = [];
|
|
395
|
+
for (const page of live) {
|
|
396
|
+
const parent = page.parentId && page.parentId !== page.id ? page.parentId : null;
|
|
397
|
+
if (!parent) roots.push(page);
|
|
398
|
+
else children.set(parent, [...children.get(parent) ?? [], page]);
|
|
399
|
+
}
|
|
400
|
+
for (const list of children.values()) list.sort(comparePagePosition);
|
|
401
|
+
roots.sort(comparePagePosition);
|
|
402
|
+
const focus = input.focusId ? byId.get(input.focusId) : void 0;
|
|
403
|
+
const drawn = /* @__PURE__ */ new Map();
|
|
404
|
+
const hiddenChildren = /* @__PURE__ */ new Map();
|
|
405
|
+
const depth = /* @__PURE__ */ new Map();
|
|
406
|
+
const queue = [];
|
|
407
|
+
const add = (page, at) => {
|
|
408
|
+
if (depth.has(page.id)) return;
|
|
409
|
+
depth.set(page.id, at);
|
|
410
|
+
drawn.set(page.id, page);
|
|
411
|
+
queue.push(page.id);
|
|
412
|
+
};
|
|
413
|
+
const center = focus ?? roots[0];
|
|
414
|
+
const rootCircleIds = promotedCircles(children, center);
|
|
415
|
+
if (center) add(center, 0);
|
|
416
|
+
if (center && !focus) for (const root of roots.slice(1, 9)) add(root, 1);
|
|
417
|
+
for (let up = focus?.parentId ? byId.get(focus.parentId) : void 0, at = 1; up; at++) {
|
|
418
|
+
if (!depth.has(up.id)) add(up, at);
|
|
419
|
+
up = up.parentId && up.parentId !== up.id ? byId.get(up.parentId) : void 0;
|
|
420
|
+
}
|
|
421
|
+
while (queue.length) {
|
|
422
|
+
const id = queue.shift();
|
|
423
|
+
const page = drawn.get(id);
|
|
424
|
+
const at = depth.get(id);
|
|
425
|
+
if (at >= 3 || at === 2 && !rootCircleIds.has(id)) continue;
|
|
426
|
+
const parent = page.parentId ? byId.get(page.parentId) : void 0;
|
|
427
|
+
if (parent) add(parent, at + 1);
|
|
428
|
+
const kids = children.get(id) ?? [];
|
|
429
|
+
if (!input.loadedParents.has(id)) {
|
|
430
|
+
const count = page.childCount ?? 0;
|
|
431
|
+
const stand = Math.min(count, 8);
|
|
432
|
+
for (let index = 0; index < stand; index++) {
|
|
433
|
+
const placeholder = syntheticPage(`${PLACEHOLDER_PREFIX}${id}:${index}`, page, { name: `${page.childCountCapped ? `${count}+` : count} ${count === 1 ? "page" : "pages"} under ${page.name}` });
|
|
434
|
+
drawn.set(placeholder.id, placeholder);
|
|
435
|
+
depth.set(placeholder.id, at + 1);
|
|
436
|
+
}
|
|
437
|
+
if (!kids.length) continue;
|
|
438
|
+
}
|
|
439
|
+
const byType = /* @__PURE__ */ new Map();
|
|
440
|
+
for (const kid of kids) {
|
|
441
|
+
const type = scopeType(kid);
|
|
442
|
+
if (type) byType.set(type, [...byType.get(type) ?? [], kid]);
|
|
443
|
+
}
|
|
444
|
+
const grouped = /* @__PURE__ */ new Set();
|
|
445
|
+
if (id !== center?.id) for (const [type, members] of byType) {
|
|
446
|
+
const groupId = `${GROUP_PREFIX}${id}:${type}`;
|
|
447
|
+
if (members.length < 3 || input.openGroups.has(groupId)) continue;
|
|
448
|
+
for (const member of members) grouped.add(member.id);
|
|
449
|
+
const group = syntheticPage(groupId, page, {
|
|
450
|
+
isScope: true,
|
|
451
|
+
address: `${type}:*`,
|
|
452
|
+
displayLabel: `${type} scopes`,
|
|
453
|
+
name: `${members.length} ${type} scopes`,
|
|
454
|
+
childCount: members.length
|
|
455
|
+
});
|
|
456
|
+
drawn.set(group.id, group);
|
|
457
|
+
depth.set(group.id, at + 1);
|
|
458
|
+
}
|
|
459
|
+
const shown = kids.filter((kid) => !grouped.has(kid.id));
|
|
460
|
+
let drawnKids = 0;
|
|
461
|
+
for (const kid of shown) {
|
|
462
|
+
if (depth.has(kid.id)) {
|
|
463
|
+
drawnKids++;
|
|
464
|
+
continue;
|
|
465
|
+
}
|
|
466
|
+
if (drawnKids >= cap + (input.revealed?.get(id) ?? 0)) break;
|
|
467
|
+
add(kid, at + 1);
|
|
468
|
+
drawnKids++;
|
|
469
|
+
}
|
|
470
|
+
if (input.loadedParents.has(id)) {
|
|
471
|
+
const total = Math.max(page.childCount ?? kids.length, kids.length);
|
|
472
|
+
const hidden = Math.max(0, total - drawnKids - grouped.size);
|
|
473
|
+
hiddenChildren.set(id, {
|
|
474
|
+
hidden,
|
|
475
|
+
drawn: drawnKids
|
|
476
|
+
});
|
|
477
|
+
if (hidden > 0 && id === center?.id) {
|
|
478
|
+
const rest = syntheticPage(`${REST_PREFIX}${id}`, page, {
|
|
479
|
+
name: `+${page.childCountCapped ? `${total}+` : hidden} more`,
|
|
480
|
+
childCount: hidden
|
|
481
|
+
});
|
|
482
|
+
drawn.set(rest.id, rest);
|
|
483
|
+
depth.set(rest.id, at + 1);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
}
|
|
487
|
+
const wanted = focus ? [focus.id, ...focus.parentId && focus.parentId !== focus.id ? [focus.parentId] : []] : roots.map((root) => root.id);
|
|
488
|
+
const circles = [...depth].filter(([id, at]) => (at <= 1 || rootCircleIds.has(id)) && !wanted.includes(id)).map(([id]) => drawn.get(id)).filter((page) => (page.childCount ?? 0) > 0 && !isScopeGroup(page) && !isChildPlaceholder(page) && !isRestCircle(page));
|
|
489
|
+
wanted.push(...circles.slice(0, 24).map((page) => page.id));
|
|
490
|
+
return {
|
|
491
|
+
pages: [...drawn.values()],
|
|
492
|
+
hiddenChildren,
|
|
493
|
+
wanted,
|
|
494
|
+
hub: center?.id ?? null
|
|
495
|
+
};
|
|
496
|
+
}
|
|
497
|
+
export { BRANCH_COLORS, CROWD_MIN_SCALE, CROWD_START, FULL_CIRCLE_DEPTH, GRAPH_CHILD_CAP, HIGHER_LEVEL_CAP, KNOWLEDGE_COUNTED_DOT_SIZE, KNOWLEDGE_DOT_HIT_MARGIN, KNOWLEDGE_DOT_SIZE, PLACEHOLDER_CAP, READABLE_MIN_ZOOM, REST_BATCH, ROOT_CIRCLE_CAP, SCOPE_GROUP_MIN, SIBLING_ROOT_CAP, WANTED_CIRCLE_CAP, branchColors, crowdScale, graphShape, isChildPlaceholder, isRestCircle, isScopeGroup, lazyGraph, promotedCircles, radialLayout };
|
|
498
|
+
|
|
499
|
+
//# sourceMappingURL=graphShape.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"graphShape.es.js","names":[],"sources":["../../../../src/domains/knowledge/lib/graphShape.ts"],"sourcesContent":["/**\n * The graph's shape around one focused page: how far each page sits from the focus along parent links,\n * which pages draw as full labelled circles and which as small dots, and where each one goes on a\n * radial layout. Pure, so the depth rule and the layout are unit-tested without React Flow.\n */\n\nimport type { KnowledgePagePayload } from '../pageTypes';\nimport { comparePagePosition } from './pageTree';\n\n/** Why a page far from the focus still draws as a labelled circle. */\nexport type GraphLevel = 'scope' | 'ancestor';\n\n/** Most scopes and ancestors beyond the first ring that draw as circles; any more fall back to dots. */\nexport const HIGHER_LEVEL_CAP = 10;\n\n/** Full circles carry a label; dots are small coloured markers that name themselves on hover. */\nexport type GraphNodeForm = 'full' | 'dot';\n\n/** Pages at most this many parent links from the focus draw as full circles. */\nexport const FULL_CIRCLE_DEPTH = 1;\n\n/**\n * How many pages one level farther out than the usual circles still draw as circles, so a page with no\n * children reads like a focused scope instead of a ring of bare dots. The rest of that level, and the level\n * below, are dots.\n */\nexport const ROOT_CIRCLE_CAP = 8;\n\n/**\n * The pages promoted to circles at depth two: for a centre with no children, its first siblings, the children\n * of its parent, since those are the pages around it. A centre with children needs no promotion: its own\n * children are the circles.\n */\nexport function promotedCircles(\n children: ReadonlyMap<string, readonly KnowledgePagePayload[]>,\n center: KnowledgePagePayload | undefined,\n): Set<string> {\n const promoted = new Set<string>();\n if (center && !(children.get(center.id)?.length ?? 0) && !(center.childCount ?? 0)) {\n if (center.parentId && center.parentId !== center.id) {\n (children.get(center.parentId) ?? [])\n .filter(child => child.id !== center.id && !isChildPlaceholder(child))\n .slice(0, ROOT_CIRCLE_CAP)\n .forEach(child => promoted.add(child.id));\n }\n }\n return promoted;\n}\n\n/** A dot's diameter. */\nexport const KNOWLEDGE_DOT_SIZE = 20;\n/** A dot's diameter when it carries its link count. */\nexport const KNOWLEDGE_COUNTED_DOT_SIZE = 28;\n\n/** How far past its edge a dot still counts as under the pointer. */\nexport const KNOWLEDGE_DOT_HIT_MARGIN = 8;\n\nconst PLACEHOLDER_PREFIX = 'more:';\nconst REST_PREFIX = 'rest:';\nconst GROUP_PREFIX = 'group:';\n\n/** A stand-in dot for a child that hasn't loaded yet; `parentId` is the page whose children it stands for. */\nexport function isChildPlaceholder(page: Pick<KnowledgePagePayload, 'id'>): boolean {\n return page.id.startsWith(PLACEHOLDER_PREFIX);\n}\n\n/** The circle that says how many more children the centre has than are drawn; it opens nothing. */\nexport function isRestCircle(page: Pick<KnowledgePagePayload, 'id'>): boolean {\n return page.id.startsWith(REST_PREFIX);\n}\n\n/** One circle standing for several sibling scopes of one type, e.g. a resource's memory threads. */\nexport function isScopeGroup(page: Pick<KnowledgePagePayload, 'id'>): boolean {\n return page.id.startsWith(GROUP_PREFIX);\n}\n\nexport interface GraphShape {\n /** Parent links between each page and the focus; the focus is 0. Pages the focus can't reach are left out. */\n depth: Map<string, number>;\n form: Map<string, GraphNodeForm>;\n /** The page one link from the focus that each farther page hangs under, so its dot takes that branch's colour. */\n branch: Map<string, string>;\n /** The page each one was reached from, walking out from the focus. */\n via: Map<string, string | null>;\n /** Pages that sit above others and always draw as labelled circles: scopes, and the focus's ancestors. */\n level: Map<string, GraphLevel>;\n /** The focus's link ends drawn as circles: farther pages, not neighbours in the hierarchy. */\n linked: Set<string>;\n /** The page the layout centres on: the focus, else the first root; `null` only when there are no pages. */\n center: string | null;\n}\n\nfunction liveOnly(pages: readonly KnowledgePagePayload[]) {\n return pages.filter(page => !page.deletedAt && !page.mergedInto);\n}\n\n/**\n * Walks parent links out from `focusId` (or, with no focus, from the roots), so each page's depth is how\n * many links it sits from the focus, whichever way they run: the focus's parent and its children are 1,\n * its siblings and grandchildren 2. The focus and pages within {@link FULL_CIRCLE_DEPTH} are full circles;\n * every other page, every page the walk never reaches, and every placeholder is a dot. With no focus the\n * first root becomes the centre and the other roots sit one link from it. A root is any page whose parent is not loaded, so a page cut off from its parent by a bounded graph is a root too.\n */\nexport function graphShape(\n pages: readonly KnowledgePagePayload[],\n focusId: string | null,\n linkEnds: ReadonlySet<string> = noPages,\n): GraphShape {\n const live = liveOnly(pages);\n const byId = new Map(live.map(page => [page.id, page]));\n const children = new Map<string, KnowledgePagePayload[]>();\n const roots: KnowledgePagePayload[] = [];\n for (const page of live) {\n const parent = page.parentId && page.parentId !== page.id ? byId.get(page.parentId) : undefined;\n if (!parent) roots.push(page);\n else children.set(parent.id, [...(children.get(parent.id) ?? []), page]);\n }\n for (const list of children.values()) list.sort(comparePagePosition);\n roots.sort(comparePagePosition);\n\n const center = focusId && byId.has(focusId) ? focusId : (roots[0]?.id ?? null);\n const centerPage = center ? byId.get(center) : undefined;\n const depth = new Map<string, number>();\n const branch = new Map<string, string>();\n const via = new Map<string, string | null>();\n const queue: string[] = [];\n const visit = (id: string, from: string | null, at: number, fromBranch: string | undefined) => {\n if (depth.has(id)) return;\n depth.set(id, at);\n via.set(id, from);\n const own = at === 1 ? id : fromBranch;\n if (own) branch.set(id, own);\n queue.push(id);\n };\n if (center) visit(center, null, 0, undefined);\n else for (const root of roots) visit(root.id, null, 1, undefined);\n while (queue.length) {\n const id = queue.shift() as string;\n const at = depth.get(id) as number;\n const page = byId.get(id);\n const parentId = page?.parentId && byId.has(page.parentId) ? page.parentId : null;\n // Parent first, so a focused page's parent takes the first slot on the ring.\n if (parentId) visit(parentId, id, at + 1, branch.get(id));\n for (const child of children.get(id) ?? []) visit(child.id, id, at + 1, branch.get(id));\n // A root at the centre sits among the other roots, each a circle of its own beside its children.\n if (id === center && centerPage && roots.includes(centerPage)) {\n for (const root of roots) if (root.id !== center) visit(root.id, id, at + 1, root.id);\n }\n }\n\n // Scopes and the path up from the focus are the graph's higher levels: they read as circles, not dots.\n const level = new Map<string, GraphLevel>();\n for (let up = focusId ? byId.get(focusId)?.parentId : undefined; up && !level.has(up);) {\n const above = byId.get(up);\n if (!above) break;\n level.set(above.id, above.isScope ? 'scope' : 'ancestor');\n up = above.parentId && above.parentId !== above.id ? above.parentId : undefined;\n }\n for (const page of live) {\n if (page.isScope && !isScopeGroup(page) && !isChildPlaceholder(page) && depth.has(page.id)) {\n level.set(page.id, 'scope');\n }\n }\n const rootCircles = promotedCircles(children, centerPage);\n const form = new Map<string, GraphNodeForm>();\n const linked = new Set<string>();\n let farCircles = 0;\n for (const page of live) {\n const at = depth.get(page.id);\n const near = at !== undefined && (at <= FULL_CIRCLE_DEPTH || rootCircles.has(page.id)) && !isChildPlaceholder(page);\n const higher = at !== undefined && level.has(page.id) && !isChildPlaceholder(page);\n // The focus's own link ends are as much its neighbours as its children: they read as named circles too.\n const linkedEnd = at === undefined && linkEnds.has(page.id) && !isChildPlaceholder(page);\n if (linkedEnd) linked.add(page.id);\n form.set(page.id, near || linkedEnd || (higher && farCircles++ < HIGHER_LEVEL_CAP) ? 'full' : 'dot');\n }\n return { depth, form, branch, via, level, linked, center };\n}\n\ntype Point = { x: number; y: number };\n\n/** Radius of the first ring: at least this, more when its full circles need the room. */\nconst FIRST_RING = 230;\n/** Widest the first ring of full circles grows before they stagger over more rows. */\nconst MAX_CIRCLE_RING = 300;\n/** Gap from the full-circle ring out to the first ring of dots. */\nconst FIRST_DOT_RING_GAP = 150;\n/** Gap between rings of dots. */\nconst DOT_RING_GAP = 70;\n/** Space a dot needs along its ring before the next one staggers outward. */\nconst DOT_SPACING = 28;\n/** Space kept clear between the focus, its link-end circles and the first ring around them. */\nconst LINK_GAP = 16;\n/** The ring of link-end circles grows to hold this many before they stack into more rows. */\nconst LINK_RING_WIDEST = 260;\nconst noPages: ReadonlySet<string> = new Set();\n\n/**\n * Places the focus's link-end circles on rings around it, inside the first ring. Each circle keeps clear of\n * the focus, of the line from the focus to every page on the first ring (its parent and children) and of\n * its neighbours, so the angles those lines run at are skipped and the circles fill the gaps between them;\n * when the gaps on a ring are full the rest stack onto a ring outside it. `reach` is how far out the\n * outermost circle's edge sits.\n */\nfunction layoutLinkEnds(\n ends: readonly KnowledgePagePayload[],\n center: string,\n positions: ReadonlyMap<string, Point>,\n firstRing: readonly string[],\n sizeOf: (page: KnowledgePagePayload) => number,\n): { points: Map<string, Point>; reach: number } {\n const half = Math.max(...ends.map(page => sizeOf(page))) / 2;\n const blocked = firstRing.flatMap(id => {\n const at = positions.get(id);\n return at ? [Math.atan2(at.y, at.x)] : [];\n });\n const points = new Map<string, Point>();\n let remaining = [...ends];\n // The first ring starts clear of the focus, which draws a little larger than a circle of its own size.\n let radius = half * 2.5 + LINK_GAP;\n let reach = radius + half;\n for (let rows = 0; remaining.length && rows < 12; rows++) {\n // Angles on this ring that a line to the first ring passes through are off limits.\n const margin = Math.asin(Math.min(1, (half + LINK_GAP / 2) / radius));\n const step = 2 * Math.asin(Math.min(1, (half * 2 + LINK_GAP) / (2 * radius)));\n const gaps = blocked.length ? [...blocked].sort((a, b) => a - b) : [-Math.PI];\n const slots: number[] = [];\n gaps.forEach((from, index) => {\n const next = gaps[(index + 1) % gaps.length] as number;\n const start = from + margin;\n const end = (index + 1 < gaps.length ? next : next + 2 * Math.PI) - margin;\n for (let angle = start; angle <= end + 1e-9; angle += step) slots.push(angle);\n });\n const used = remaining.splice(0, Math.max(1, slots.length));\n used.forEach((page, index) => {\n // A ring with no gap left puts its one circle at angle 0; the next ring is wider, so it stays clear.\n const angle = slots[index] ?? slots[0] ?? 0;\n points.set(page.id, { x: Math.cos(angle) * radius, y: Math.sin(angle) * radius });\n });\n reach = radius + half;\n radius += half * 2 + LINK_GAP;\n }\n return { points, reach };\n}\n\n/**\n * Places the focus at the centre and every other page on the ring for its depth, each page's children in\n * a slice of the circle taken out of its parent's slice, sized by how much hangs under each one (a full\n * circle counts for more than a dot). The focus's parent gets the slice at the top. Dots that don't fit\n * along their ring stagger outward in rows. Pages the walk never reached go on one outer ring, except\n * those in `near` (the focus's links), which sit on a ring close around the focus so they stay in view.\n */\nexport function radialLayout(\n pages: readonly KnowledgePagePayload[],\n shape: GraphShape,\n sizeOf: (page: KnowledgePagePayload) => number,\n near: ReadonlySet<string> = noPages,\n): Map<string, Point> {\n const live = liveOnly(pages);\n const byId = new Map(live.map(page => [page.id, page]));\n // In the order the walk reached them, which graphShape keeps in position order: the input's order never matters.\n const kids = new Map<string | null, string[]>();\n for (const id of shape.depth.keys()) {\n if (!byId.has(id) || id === shape.center) continue;\n const from = shape.via.get(id) ?? null;\n kids.set(from, [...(kids.get(from) ?? []), id]);\n }\n const weight = new Map<string, number>();\n const weigh = (id: string): number => {\n const own = shape.form.get(id) === 'full' ? 4 : 1;\n const below = (kids.get(id) ?? []).reduce((sum, kid) => sum + weigh(kid), 0);\n const total = Math.max(own, below);\n weight.set(id, total);\n return total;\n };\n const firstRing = shape.center ? (kids.get(shape.center) ?? []) : (kids.get(null) ?? []);\n firstRing.forEach(weigh);\n\n // Ring radii: the first fits its full circles side by side; dot rings sit beyond it.\n // A ring of full circles is wide enough for them side by side; the ring after one leaves room for their size.\n const circleWidth = new Map<number, number>();\n for (const [id, at] of shape.depth) {\n const page = byId.get(id);\n if (!page || id === shape.center || shape.form.get(id) !== 'full') continue;\n circleWidth.set(at, (circleWidth.get(at) ?? 0) + sizeOf(page) + 30);\n }\n // Circles that would need a huge ring to sit side by side stagger over a few rows instead, so the\n // whole first level stays within reach of the centre at a readable zoom.\n const firstWidth = circleWidth.get(1) ?? 0;\n const ringRows = Math.max(1, Math.ceil(firstWidth / (2 * Math.PI * MAX_CIRCLE_RING)));\n const fullCount = [...shape.depth].filter(\n ([id, at]) => at === 1 && id !== shape.center && shape.form.get(id) === 'full' && byId.has(id),\n ).length;\n const rowStep = fullCount ? firstWidth / fullCount : 0;\n const radii = [0, Math.max(FIRST_RING, firstWidth / ringRows / (2 * Math.PI))];\n const radius = (at: number) => {\n while (radii.length <= at) {\n const next = radii.length;\n const last = radii[next - 1] as number;\n const gap = circleWidth.has(next - 1) && next > 1 ? FIRST_DOT_RING_GAP : DOT_RING_GAP;\n const outer = next === 2 ? (ringRows - 1) * rowStep : 0;\n radii.push(Math.max(last + gap + outer, (circleWidth.get(next) ?? 0) / (2 * Math.PI)));\n }\n return radii[at] as number;\n };\n let circleIndex = 0;\n\n const positions = new Map<string, Point>();\n const place = (ids: string[], at: number, start: number, span: number) => {\n const total = ids.reduce((sum, id) => sum + (weight.get(id) ?? 1), 0) || 1;\n // Dots that won't fit side by side along the arc stagger outward in rows.\n const dots = ids.filter(id => shape.form.get(id) !== 'full').length;\n const arc = span * radius(at);\n const perRow = Math.max(1, Math.floor(arc / DOT_SPACING));\n let angle = start;\n let dotIndex = 0;\n for (const id of ids) {\n const share = ((weight.get(id) ?? 1) / total) * span;\n const middle = angle + share / 2;\n const full = shape.form.get(id) === 'full';\n const row = full || dots <= perRow ? 0 : dotIndex % Math.ceil(dots / perRow);\n if (!full) dotIndex++;\n const r = radius(at) + (full && at === 1 ? (circleIndex++ % ringRows) * rowStep : row * DOT_SPACING);\n positions.set(id, { x: Math.cos(middle) * r, y: Math.sin(middle) * r });\n place(kids.get(id) ?? [], at + 1, angle, share);\n angle += share;\n }\n };\n // The first slice is centred at the top, where the focus's parent (always first) lands.\n const firstShare = firstRing.length\n ? ((weight.get(firstRing[0] as string) ?? 1) / firstRing.reduce((s, id) => s + (weight.get(id) ?? 1), 0)) *\n 2 *\n Math.PI\n : 0;\n const run = () => {\n positions.clear();\n circleIndex = 0;\n if (shape.center) positions.set(shape.center, { x: 0, y: 0 });\n place(firstRing, 1, -Math.PI / 2 - firstShare / 2, 2 * Math.PI);\n };\n run();\n\n const unreached = live.filter(page => !positions.has(page.id)).sort((a, b) => (a.id < b.id ? -1 : 1));\n const close = unreached.filter(page => near.has(page.id) && shape.form.get(page.id) === 'full');\n const linkDots = unreached.filter(page => near.has(page.id) && shape.form.get(page.id) !== 'full');\n let linkRingReach = 0;\n const parentId = shape.center ? byId.get(shape.center)?.parentId : undefined;\n const hasChildren = firstRing.some(id => id !== parentId);\n if (close.length && shape.center && hasChildren) {\n // A focus with children keeps its ring to them: pages in other branches go on a ring beyond the\n // children and the dots under them, a link from the centre crossing that band to reach each one.\n const half = Math.max(...close.map(page => sizeOf(page))) / 2;\n let extent = 0;\n for (const [id, point] of positions) {\n const page = byId.get(id);\n if (page) extent = Math.max(extent, Math.hypot(point.x, point.y) + sizeOf(page) / 2);\n }\n const ring = Math.max(extent + LINK_GAP + half, (close.length * (half * 2 + LINK_GAP)) / (2 * Math.PI));\n // Start opposite the focus's parent, which sits at the top, and go round.\n close.forEach((page, index) => {\n const angle = Math.PI / 2 + (index / close.length) * 2 * Math.PI;\n positions.set(page.id, { x: Math.cos(angle) * ring, y: Math.sin(angle) * ring });\n });\n linkRingReach = ring + half;\n } else if (close.length && shape.center) {\n const linked = layoutLinkEnds(close, shape.center, positions, firstRing, sizeOf);\n // The first ring and everything beyond it make room for the circles inside it.\n const firstSize = Math.max(\n 0,\n ...firstRing.filter(id => shape.form.get(id) === 'full').map(id => sizeOf(byId.get(id) as KnowledgePagePayload)),\n );\n radii.length = 2;\n radii[1] = Math.max(radii[1] as number, linked.reach + LINK_GAP + firstSize / 2);\n run();\n const relinked = layoutLinkEnds(close, shape.center, positions, firstRing, sizeOf);\n for (const [id, point] of relinked.points) positions.set(id, point);\n }\n const closeDots = linkDots;\n const closeRing = Math.min(175, Math.max(120, (closeDots.length * DOT_SPACING) / (2 * Math.PI)));\n closeDots.forEach((page, index) => {\n // Half a step off the top, where the focus's parent sits.\n const angle = Math.PI / 2 + (index / closeDots.length) * 2 * Math.PI;\n positions.set(page.id, { x: Math.cos(angle) * closeRing, y: Math.sin(angle) * closeRing });\n });\n const far = unreached.filter(page => !near.has(page.id));\n if (far.length) {\n const outer = Math.max(radius(radii.length), linkRingReach) + DOT_RING_GAP;\n far.forEach((page, index) => {\n const angle = -Math.PI / 2 + (index / far.length) * 2 * Math.PI;\n positions.set(page.id, { x: Math.cos(angle) * outer, y: Math.sin(angle) * outer });\n });\n }\n return positions;\n}\n\n/** Colours for the dots of each branch around the focus, in branch order. */\nexport const BRANCH_COLORS = [\n 'var(--chart-blue)',\n 'var(--chart-green)',\n 'var(--chart-amber)',\n 'var(--chart-pink)',\n 'var(--chart-cyan)',\n 'var(--chart-orange)',\n 'var(--chart-purple)',\n 'var(--chart-red)',\n];\n\n/** One colour per branch, in the order the branches sit around the focus. */\nexport function branchColors(pages: readonly KnowledgePagePayload[], shape: GraphShape): Map<string, string> {\n const order: string[] = [];\n for (const page of pages) {\n const own = shape.branch.get(page.id);\n if (own && !order.includes(own)) order.push(own);\n }\n return new Map(order.map((id, index) => [id, BRANCH_COLORS[index % BRANCH_COLORS.length] as string]));\n}\n\n/** Framing never zooms out past this, so circle names stay readable; a bigger graph is panned, not shrunk. */\nexport const READABLE_MIN_ZOOM = 0.7;\n/** Children a drawn page shows at most; the rest are counted, not drawn. */\nexport const GRAPH_CHILD_CAP = 48;\n/** How many more children a click on a \"+N more\" circle draws. */\nexport const REST_BATCH = 12;\n/** Stand-in dots drawn at most for a page whose children haven't loaded yet. */\nexport const PLACEHOLDER_CAP = 8;\n/** Most circles whose children are loaded just to draw them as dots around it. */\nexport const WANTED_CIRCLE_CAP = 24;\n/** Roots drawn beside the root at the centre when nothing is focused. */\nexport const SIBLING_ROOT_CAP = 8;\n/** Children around a page that fit at full size; past this the circles shrink to make room. */\nexport const CROWD_START = 16;\n/** Smallest a crowded ring's circles shrink to, as a fraction of their usual size. */\nexport const CROWD_MIN_SCALE = 0.7;\n\n/** How much to shrink each of `count` circles sharing a ring, so a page with dozens of children still fits. */\nexport function crowdScale(count: number): number {\n if (count <= CROWD_START) return 1;\n return Math.max(CROWD_MIN_SCALE, Math.sqrt(CROWD_START / count));\n}\n\n/** Sibling scopes of one type (e.g. `thread`) collapse into one circle from this many. */\nexport const SCOPE_GROUP_MIN = 3;\n\nconst nobody = { author: '' };\n\nfunction syntheticPage(id: string, parent: KnowledgePagePayload, fields: Partial<KnowledgePagePayload>) {\n return {\n id,\n scopeId: parent.scopeId,\n parentId: parent.id,\n isScope: false,\n position: '',\n name: '',\n version: 0,\n createdBy: nobody,\n updatedBy: nobody,\n createdAt: '',\n updatedAt: '',\n ...fields,\n } satisfies KnowledgePagePayload;\n}\n\n/** The type part of a scope address (`thread` in `thread:abc`), or `null` for a page or an untyped scope. */\nfunction scopeType(page: KnowledgePagePayload): string | null {\n if (!page.isScope || !page.address) return null;\n const colon = page.address.indexOf(':');\n return colon > 0 ? page.address.slice(0, colon) : null;\n}\n\nexport interface LazyGraphInput {\n /** Every page loaded so far (tree levels, the focused page's path), live or not. */\n pages: readonly KnowledgePagePayload[];\n /** Parents whose first level of children has loaded; `rootKey` stands for the root scopes. */\n loadedParents: ReadonlySet<string>;\n rootKey: string;\n focusId: string | null;\n /** Scope groups the user opened, by group id. */\n openGroups: ReadonlySet<string>;\n /** Children drawn past the cap, per parent: what clicks on its \"+N more\" circle have revealed. */\n revealed?: ReadonlyMap<string, number>;\n cap?: number;\n}\n\nexport interface LazyGraph {\n pages: KnowledgePagePayload[];\n /** Per drawn page whose children have loaded: how many of them are drawn and how many are not. */\n hiddenChildren: Map<string, { hidden: number; drawn: number }>;\n /** Pages the graph wants the next level of: the focus and its parent, or the roots with no focus. */\n wanted: string[];\n /** The page the layout centres on: the focus, or with nothing focused the first root scope. */\n hub: string | null;\n}\n\n/**\n * What a lazily loaded graph draws: the focus (or the root scopes), everything within two parent links\n * of it, and the focus's path up to its root. A page's children are capped; sibling scopes of one type\n * past {@link SCOPE_GROUP_MIN} collapse into one group circle unless opened (never under the focus\n * itself); a full-circle page whose children haven't loaded gets stand-in dots, one per child up to\n * {@link PLACEHOLDER_CAP}.\n */\nexport function lazyGraph(input: LazyGraphInput): LazyGraph {\n const cap = input.cap ?? GRAPH_CHILD_CAP;\n const live = liveOnly(input.pages);\n const byId = new Map(live.map(page => [page.id, page]));\n const children = new Map<string, KnowledgePagePayload[]>();\n const roots: KnowledgePagePayload[] = [];\n for (const page of live) {\n const parent = page.parentId && page.parentId !== page.id ? page.parentId : null;\n if (!parent) roots.push(page);\n else children.set(parent, [...(children.get(parent) ?? []), page]);\n }\n for (const list of children.values()) list.sort(comparePagePosition);\n roots.sort(comparePagePosition);\n\n const focus = input.focusId ? byId.get(input.focusId) : undefined;\n const drawn = new Map<string, KnowledgePagePayload>();\n const hiddenChildren = new Map<string, { hidden: number; drawn: number }>();\n const depth = new Map<string, number>();\n const queue: string[] = [];\n const add = (page: KnowledgePagePayload, at: number) => {\n if (depth.has(page.id)) return;\n depth.set(page.id, at);\n drawn.set(page.id, page);\n queue.push(page.id);\n };\n // With nothing focused the first root scope is the hub, drawn exactly as a focused scope is; the other\n // roots sit beside its children.\n const center = focus ?? roots[0];\n // Pages one level out that draw as circles too, with their own children drawn as dots.\n const rootCircleIds = promotedCircles(children, center);\n if (center) add(center, 0);\n if (center && !focus) for (const root of roots.slice(1, 1 + SIBLING_ROOT_CAP)) add(root, 1);\n // The path up from the focus, however far, so it is clear where the focus sits.\n for (let up = focus?.parentId ? byId.get(focus.parentId) : undefined, at = 1; up; at++) {\n if (!depth.has(up.id)) add(up, at);\n up = up.parentId && up.parentId !== up.id ? byId.get(up.parentId) : undefined;\n }\n\n while (queue.length) {\n const id = queue.shift() as string;\n const page = drawn.get(id) as KnowledgePagePayload;\n const at = depth.get(id) as number;\n if (at >= 3 || (at === 2 && !rootCircleIds.has(id))) continue;\n const parent = page.parentId ? byId.get(page.parentId) : undefined;\n if (parent) add(parent, at + 1);\n const kids = children.get(id) ?? [];\n if (!input.loadedParents.has(id)) {\n const count = page.childCount ?? 0;\n const stand = Math.min(count, PLACEHOLDER_CAP);\n for (let index = 0; index < stand; index++) {\n const placeholder = syntheticPage(`${PLACEHOLDER_PREFIX}${id}:${index}`, page, {\n name: `${page.childCountCapped ? `${count}+` : count} ${count === 1 ? 'page' : 'pages'} under ${page.name}`,\n });\n drawn.set(placeholder.id, placeholder);\n depth.set(placeholder.id, at + 1);\n }\n if (!kids.length) continue;\n }\n // Sibling scopes of one type collapse into a group circle, except under the focus.\n const byType = new Map<string, KnowledgePagePayload[]>();\n for (const kid of kids) {\n const type = scopeType(kid);\n if (type) byType.set(type, [...(byType.get(type) ?? []), kid]);\n }\n const grouped = new Set<string>();\n if (id !== center?.id) {\n for (const [type, members] of byType) {\n const groupId = `${GROUP_PREFIX}${id}:${type}`;\n if (members.length < SCOPE_GROUP_MIN || input.openGroups.has(groupId)) continue;\n for (const member of members) grouped.add(member.id);\n const group = syntheticPage(groupId, page, {\n isScope: true,\n address: `${type}:*`,\n displayLabel: `${type} scopes`,\n name: `${members.length} ${type} scopes`,\n childCount: members.length,\n });\n drawn.set(group.id, group);\n depth.set(group.id, at + 1);\n }\n }\n const shown = kids.filter(kid => !grouped.has(kid.id));\n let drawnKids = 0;\n for (const kid of shown) {\n if (depth.has(kid.id)) {\n drawnKids++;\n continue;\n }\n if (drawnKids >= cap + (input.revealed?.get(id) ?? 0)) break;\n add(kid, at + 1);\n drawnKids++;\n }\n if (input.loadedParents.has(id)) {\n const total = Math.max(page.childCount ?? kids.length, kids.length);\n const hidden = Math.max(0, total - drawnKids - grouped.size);\n hiddenChildren.set(id, { hidden, drawn: drawnKids });\n if (hidden > 0 && id === center?.id) {\n const rest = syntheticPage(`${REST_PREFIX}${id}`, page, {\n name: `+${page.childCountCapped ? `${total}+` : hidden} more`,\n childCount: hidden,\n });\n drawn.set(rest.id, rest);\n depth.set(rest.id, at + 1);\n }\n }\n }\n\n const wanted = focus\n ? [focus.id, ...(focus.parentId && focus.parentId !== focus.id ? [focus.parentId] : [])]\n : roots.map(root => root.id);\n // One level beyond the circles: the children of the pages drawn as circles, so their own children show as dots.\n const circles = [...depth]\n .filter(([id, at]) => (at <= 1 || rootCircleIds.has(id)) && !wanted.includes(id))\n .map(([id]) => drawn.get(id) as KnowledgePagePayload)\n .filter(\n page => (page.childCount ?? 0) > 0 && !isScopeGroup(page) && !isChildPlaceholder(page) && !isRestCircle(page),\n );\n wanted.push(...circles.slice(0, WANTED_CIRCLE_CAP).map(page => page.id));\n return { pages: [...drawn.values()], hiddenChildren, wanted, hub: center?.id ?? null };\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
// src/domains/knowledge/lib/linkCountsText.ts
|
|
3
|
+
/** `4 links in, 14 links out`: what the arrows in a link badge say, for its label and a page's tooltip. */
|
|
4
|
+
function linkCountsText(links, notShown = 0) {
|
|
5
|
+
const noun = (count) => count === 1 ? "link" : "links";
|
|
6
|
+
const text = `${links.in} ${noun(links.in)} in, ${links.out} ${noun(links.out)} out`;
|
|
7
|
+
return notShown > 0 ? `${text} (${notShown} not shown)` : text;
|
|
8
|
+
}
|
|
9
|
+
exports.linkCountsText = linkCountsText;
|
|
10
|
+
|
|
11
|
+
//# sourceMappingURL=linkCountsText.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkCountsText.cjs.js","names":[],"sources":["../../../../src/domains/knowledge/lib/linkCountsText.ts"],"sourcesContent":["/** `4 links in, 14 links out`: what the arrows in a link badge say, for its label and a page's tooltip. */\nexport function linkCountsText(links: { in: number; out: number }, notShown = 0): string {\n const noun = (count: number) => (count === 1 ? 'link' : 'links');\n const text = `${links.in} ${noun(links.in)} in, ${links.out} ${noun(links.out)} out`;\n return notShown > 0 ? `${text} (${notShown} not shown)` : text;\n}\n"],"mappings":";;;AACA,SAAgB,eAAe,OAAoC,WAAW,GAAW;CACvF,MAAM,QAAQ,UAAmB,UAAU,IAAI,SAAS;CACxD,MAAM,OAAO,GAAG,MAAM,GAAG,GAAG,KAAK,MAAM,EAAE,EAAE,OAAO,MAAM,IAAI,GAAG,KAAK,MAAM,GAAG,EAAE;CAC/E,OAAO,WAAW,IAAI,GAAG,KAAK,IAAI,SAAS,eAAe;AAC5D"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '../../../src/domains/knowledge/lib/linkCountsText';
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// src/domains/knowledge/lib/linkCountsText.ts
|
|
2
|
+
/** `4 links in, 14 links out`: what the arrows in a link badge say, for its label and a page's tooltip. */
|
|
3
|
+
function linkCountsText(links, notShown = 0) {
|
|
4
|
+
const noun = (count) => count === 1 ? "link" : "links";
|
|
5
|
+
const text = `${links.in} ${noun(links.in)} in, ${links.out} ${noun(links.out)} out`;
|
|
6
|
+
return notShown > 0 ? `${text} (${notShown} not shown)` : text;
|
|
7
|
+
}
|
|
8
|
+
export { linkCountsText };
|
|
9
|
+
|
|
10
|
+
//# sourceMappingURL=linkCountsText.es.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"linkCountsText.es.js","names":[],"sources":["../../../../src/domains/knowledge/lib/linkCountsText.ts"],"sourcesContent":["/** `4 links in, 14 links out`: what the arrows in a link badge say, for its label and a page's tooltip. */\nexport function linkCountsText(links: { in: number; out: number }, notShown = 0): string {\n const noun = (count: number) => (count === 1 ? 'link' : 'links');\n const text = `${links.in} ${noun(links.in)} in, ${links.out} ${noun(links.out)} out`;\n return notShown > 0 ? `${text} (${notShown} not shown)` : text;\n}\n"],"mappings":";;AACA,SAAgB,eAAe,OAAoC,WAAW,GAAW;CACvF,MAAM,QAAQ,UAAmB,UAAU,IAAI,SAAS;CACxD,MAAM,OAAO,GAAG,MAAM,GAAG,GAAG,KAAK,MAAM,EAAE,EAAE,OAAO,MAAM,IAAI,GAAG,KAAK,MAAM,GAAG,EAAE;CAC/E,OAAO,WAAW,IAAI,GAAG,KAAK,IAAI,SAAS,eAAe;AAC5D"}
|