@manta-eu/react 0.2.0 → 0.3.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.
Files changed (324) hide show
  1. package/dist/components/channel-icon/index.d.ts +1 -0
  2. package/dist/components/channel-icon/index.d.ts.map +1 -1
  3. package/dist/components/channel-icon/index.js +1 -1
  4. package/dist/components/channel-icon/index.js.map +1 -1
  5. package/dist/components/datastore-management/tree.d.ts +1 -1
  6. package/dist/components/datastore-management/tree.d.ts.map +1 -1
  7. package/dist/components/datastore-management/tree.js +5 -5
  8. package/dist/components/datastore-management/tree.js.map +1 -1
  9. package/dist/components/explain-fact/ExplainFact.js +3 -3
  10. package/dist/components/explain-fact/ExplainFact.js.map +1 -1
  11. package/dist/components/planning/ActioningView.d.ts +1 -2
  12. package/dist/components/planning/ActioningView.d.ts.map +1 -1
  13. package/dist/components/planning/ActioningView.js +19 -44
  14. package/dist/components/planning/ActioningView.js.map +1 -1
  15. package/dist/components/planning/ManualActionCard.d.ts +4 -0
  16. package/dist/components/planning/ManualActionCard.d.ts.map +1 -1
  17. package/dist/components/planning/ManualActionCard.js +7 -5
  18. package/dist/components/planning/ManualActionCard.js.map +1 -1
  19. package/dist/components/planning/ManualActionList.d.ts +4 -0
  20. package/dist/components/planning/ManualActionList.d.ts.map +1 -1
  21. package/dist/components/planning/ManualActionList.js +8 -2
  22. package/dist/components/planning/ManualActionList.js.map +1 -1
  23. package/dist/components/planning/actioning-view-utils.d.ts +9 -0
  24. package/dist/components/planning/actioning-view-utils.d.ts.map +1 -1
  25. package/dist/components/planning/actioning-view-utils.js +19 -1
  26. package/dist/components/planning/actioning-view-utils.js.map +1 -1
  27. package/dist/components/planning/plan-detail-utils.d.ts.map +1 -1
  28. package/dist/components/planning/plan-detail-utils.js +2 -0
  29. package/dist/components/planning/plan-detail-utils.js.map +1 -1
  30. package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts +2 -2
  31. package/dist/components/tool-invocation-card/ListRulesResultDisplay.d.ts.map +1 -1
  32. package/dist/components/tool-invocation-card/ToolOutputRenderer.d.ts.map +1 -1
  33. package/dist/components/tool-invocation-card/ToolOutputRenderer.js +7 -4
  34. package/dist/components/tool-invocation-card/ToolOutputRenderer.js.map +1 -1
  35. package/dist/components/tool-invocation-card/types.d.ts +5 -5
  36. package/dist/components/tool-invocation-card/types.d.ts.map +1 -1
  37. package/dist/components/tool-invocation-card/types.js +5 -5
  38. package/dist/components/tool-invocation-card/types.js.map +1 -1
  39. package/dist/components/tooltip/index.d.ts +7 -0
  40. package/dist/components/tooltip/index.d.ts.map +1 -1
  41. package/dist/components/tooltip/index.js +10 -1
  42. package/dist/components/tooltip/index.js.map +1 -1
  43. package/dist/explain-fact/rule-presentation.js +2 -2
  44. package/dist/explain-fact/rule-presentation.js.map +1 -1
  45. package/dist/explain-fact/tree-model.js +2 -2
  46. package/dist/explain-fact/tree-model.js.map +1 -1
  47. package/dist/globals.css +19 -6
  48. package/dist/graph/entity-link.d.ts +14 -0
  49. package/dist/graph/entity-link.d.ts.map +1 -0
  50. package/dist/graph/entity-link.js +12 -0
  51. package/dist/graph/entity-link.js.map +1 -0
  52. package/dist/graph/graph-list-utils.d.ts +1 -0
  53. package/dist/graph/graph-list-utils.d.ts.map +1 -1
  54. package/dist/graph/graph-list-utils.js +1 -0
  55. package/dist/graph/graph-list-utils.js.map +1 -1
  56. package/dist/graph/graph-model.d.ts.map +1 -1
  57. package/dist/graph/graph-model.js +14 -5
  58. package/dist/graph/graph-model.js.map +1 -1
  59. package/dist/graph/nodes/BrandAssetAnalysisView.d.ts.map +1 -1
  60. package/dist/graph/nodes/BrandAssetAnalysisView.js +2 -1
  61. package/dist/graph/nodes/BrandAssetAnalysisView.js.map +1 -1
  62. package/dist/graph/nodes/BrandFontSuggestionView.d.ts.map +1 -1
  63. package/dist/graph/nodes/BrandFontSuggestionView.js +2 -1
  64. package/dist/graph/nodes/BrandFontSuggestionView.js.map +1 -1
  65. package/dist/graph/nodes/BrandGuidelinesView.js +1 -1
  66. package/dist/graph/nodes/BrandGuidelinesView.js.map +1 -1
  67. package/dist/graph/nodes/NodePropertyTable.d.ts +4 -2
  68. package/dist/graph/nodes/NodePropertyTable.d.ts.map +1 -1
  69. package/dist/graph/nodes/NodePropertyTable.js +12 -59
  70. package/dist/graph/nodes/NodePropertyTable.js.map +1 -1
  71. package/dist/graph/nodes/node-property-row.d.ts +30 -0
  72. package/dist/graph/nodes/node-property-row.d.ts.map +1 -0
  73. package/dist/graph/nodes/node-property-row.js +35 -0
  74. package/dist/graph/nodes/node-property-row.js.map +1 -0
  75. package/dist/graph/property-formatters.d.ts +1 -0
  76. package/dist/graph/property-formatters.d.ts.map +1 -1
  77. package/dist/graph/property-formatters.js +4 -1
  78. package/dist/graph/property-formatters.js.map +1 -1
  79. package/dist/graph/special-nodes/AttributeList.d.ts +27 -0
  80. package/dist/graph/special-nodes/AttributeList.d.ts.map +1 -0
  81. package/dist/graph/special-nodes/AttributeList.js +57 -0
  82. package/dist/graph/special-nodes/AttributeList.js.map +1 -0
  83. package/dist/graph/special-nodes/EntityPreview.d.ts +5 -0
  84. package/dist/graph/special-nodes/EntityPreview.d.ts.map +1 -0
  85. package/dist/graph/special-nodes/EntityPreview.js +19 -0
  86. package/dist/graph/special-nodes/EntityPreview.js.map +1 -0
  87. package/dist/graph/special-nodes/EntityValueChip.d.ts +11 -0
  88. package/dist/graph/special-nodes/EntityValueChip.d.ts.map +1 -0
  89. package/dist/graph/special-nodes/EntityValueChip.js +40 -0
  90. package/dist/graph/special-nodes/EntityValueChip.js.map +1 -0
  91. package/dist/graph/special-nodes/GenericView.d.ts +2 -1
  92. package/dist/graph/special-nodes/GenericView.d.ts.map +1 -1
  93. package/dist/graph/special-nodes/GenericView.js +23 -69
  94. package/dist/graph/special-nodes/GenericView.js.map +1 -1
  95. package/dist/graph/special-nodes/card-facts.d.ts +52 -0
  96. package/dist/graph/special-nodes/card-facts.d.ts.map +1 -0
  97. package/dist/graph/special-nodes/card-facts.js +189 -0
  98. package/dist/graph/special-nodes/card-facts.js.map +1 -0
  99. package/dist/graph/special-nodes/property-icons.d.ts +9 -0
  100. package/dist/graph/special-nodes/property-icons.d.ts.map +1 -0
  101. package/dist/graph/special-nodes/property-icons.js +39 -0
  102. package/dist/graph/special-nodes/property-icons.js.map +1 -0
  103. package/dist/graph/status-utils.d.ts +16 -0
  104. package/dist/graph/status-utils.d.ts.map +1 -1
  105. package/dist/graph/status-utils.js +35 -0
  106. package/dist/graph/status-utils.js.map +1 -1
  107. package/dist/graph/types.d.ts +5 -0
  108. package/dist/graph/types.d.ts.map +1 -1
  109. package/dist/hooks/use-approve-anyway.d.ts +12 -0
  110. package/dist/hooks/use-approve-anyway.d.ts.map +1 -0
  111. package/dist/hooks/use-approve-anyway.js +81 -0
  112. package/dist/hooks/use-approve-anyway.js.map +1 -0
  113. package/dist/hooks/use-connection-problems.d.ts.map +1 -1
  114. package/dist/hooks/useValidateActionPlan.d.ts.map +1 -1
  115. package/dist/ldo-ui.d.ts +2 -1
  116. package/dist/ldo-ui.d.ts.map +1 -1
  117. package/dist/ldo-ui.js +1 -0
  118. package/dist/ldo-ui.js.map +1 -1
  119. package/dist/lib/find-latest-staged-rule.js +1 -1
  120. package/dist/lib/find-latest-staged-rule.js.map +1 -1
  121. package/dist/lib/manual-actions.d.ts +2 -1
  122. package/dist/lib/manual-actions.d.ts.map +1 -1
  123. package/dist/lib/manual-actions.js +3 -2
  124. package/dist/lib/manual-actions.js.map +1 -1
  125. package/dist/lib/tool-icons.js +6 -6
  126. package/dist/lib/tool-icons.js.map +1 -1
  127. package/dist/lib/tool-names.d.ts.map +1 -1
  128. package/dist/lib/tool-names.js +0 -1
  129. package/dist/lib/tool-names.js.map +1 -1
  130. package/dist/ontology/skolem.js +2 -2
  131. package/dist/ontology/skolem.js.map +1 -1
  132. package/dist/providers/ActiveChatProvider.js +3 -1
  133. package/dist/providers/ActiveChatProvider.js.map +1 -1
  134. package/dist/providers/ChatManagerProvider.d.ts.map +1 -1
  135. package/dist/providers/ChatManagerProvider.js +3 -1
  136. package/dist/providers/ChatManagerProvider.js.map +1 -1
  137. package/dist/providers/KnowledgeGraphStateProvider.js +1 -1
  138. package/dist/providers/KnowledgeGraphStateProvider.js.map +1 -1
  139. package/dist/providers/chat-socket-auth.d.ts +7 -2
  140. package/dist/providers/chat-socket-auth.d.ts.map +1 -1
  141. package/dist/providers/chat-socket-auth.js +87 -16
  142. package/dist/providers/chat-socket-auth.js.map +1 -1
  143. package/dist/providers/index.d.ts.map +1 -1
  144. package/dist/providers/index.js +8 -1
  145. package/dist/providers/index.js.map +1 -1
  146. package/dist/routes/activity/detail/ActivityChanges.d.ts +2 -0
  147. package/dist/routes/activity/detail/ActivityChanges.d.ts.map +1 -1
  148. package/dist/routes/activity/detail/ActivityChanges.js +8 -7
  149. package/dist/routes/activity/detail/ActivityChanges.js.map +1 -1
  150. package/dist/routes/activity/detail/ActivityDetail.d.ts +1 -0
  151. package/dist/routes/activity/detail/ActivityDetail.d.ts.map +1 -1
  152. package/dist/routes/activity/detail/ActivityDetail.js +5 -4
  153. package/dist/routes/activity/detail/ActivityDetail.js.map +1 -1
  154. package/dist/routes/activity/detail/ActivityStepsRail.d.ts +1 -0
  155. package/dist/routes/activity/detail/ActivityStepsRail.d.ts.map +1 -1
  156. package/dist/routes/activity/detail/ActivityStepsRail.js +3 -2
  157. package/dist/routes/activity/detail/ActivityStepsRail.js.map +1 -1
  158. package/dist/routes/activity/detail/ActivityTimeline.js +2 -2
  159. package/dist/routes/activity/detail/ActivityTimeline.js.map +1 -1
  160. package/dist/routes/activity/detail/NoChangesMessage.d.ts +6 -0
  161. package/dist/routes/activity/detail/NoChangesMessage.d.ts.map +1 -0
  162. package/dist/routes/activity/detail/NoChangesMessage.js +10 -0
  163. package/dist/routes/activity/detail/NoChangesMessage.js.map +1 -0
  164. package/dist/routes/data-explorer/class-properties.js +2 -2
  165. package/dist/routes/data-explorer/class-properties.js.map +1 -1
  166. package/dist/routes/data-explorer/classes.js +2 -2
  167. package/dist/routes/data-explorer/classes.js.map +1 -1
  168. package/dist/routes/data-explorer/components/RawTriples.js +1 -1
  169. package/dist/routes/data-explorer/components/RawTriples.js.map +1 -1
  170. package/dist/routes/data-explorer/components/RecentTypes.js +1 -1
  171. package/dist/routes/data-explorer/components/RecentTypes.js.map +1 -1
  172. package/dist/routes/data-explorer/components/class-detail/Instances.js +1 -1
  173. package/dist/routes/data-explorer/components/class-detail/Instances.js.map +1 -1
  174. package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js +1 -1
  175. package/dist/routes/data-explorer/components/namespace-detail/NamespaceClassRow.js.map +1 -1
  176. package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js +1 -1
  177. package/dist/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.js.map +1 -1
  178. package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js +1 -1
  179. package/dist/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.js.map +1 -1
  180. package/dist/routes/data-explorer/components/record-detail/ChatPreview.js +2 -2
  181. package/dist/routes/data-explorer/components/record-detail/ChatPreview.js.map +1 -1
  182. package/dist/routes/data-explorer/recents.js +1 -1
  183. package/dist/routes/data-explorer/recents.js.map +1 -1
  184. package/dist/routes/data-explorer/shapes.js +2 -2
  185. package/dist/routes/data-explorer/shapes.js.map +1 -1
  186. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.d.ts +3 -0
  187. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.d.ts.map +1 -0
  188. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js +12 -0
  189. package/dist/routes/integrations/components/connect-forms/CanvaConnectForm.js.map +1 -0
  190. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.d.ts.map +1 -1
  191. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js +13 -6
  192. package/dist/routes/integrations/components/connect-forms/DataConnectionConnectForm.js.map +1 -1
  193. package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts +3 -0
  194. package/dist/routes/integrations/components/connect-forms/data-connection-fields.d.ts.map +1 -1
  195. package/dist/routes/integrations/components/connect-forms/data-connection-fields.js +9 -2
  196. package/dist/routes/integrations/components/connect-forms/data-connection-fields.js.map +1 -1
  197. package/dist/routes/integrations/connect-forms.d.ts +1 -0
  198. package/dist/routes/integrations/connect-forms.d.ts.map +1 -1
  199. package/dist/routes/integrations/connect-forms.js +1 -0
  200. package/dist/routes/integrations/connect-forms.js.map +1 -1
  201. package/dist/routes/integrations/connection-view.d.ts.map +1 -1
  202. package/dist/routes/integrations/connection-view.js +1 -0
  203. package/dist/routes/integrations/connection-view.js.map +1 -1
  204. package/dist/routes/integrations/types.d.ts +2 -1
  205. package/dist/routes/integrations/types.d.ts.map +1 -1
  206. package/dist/routes/integrations/types.js +1 -0
  207. package/dist/routes/integrations/types.js.map +1 -1
  208. package/dist/routes/plans/components/ActionPlanPage.d.ts.map +1 -1
  209. package/dist/routes/plans/components/ActionPlanPage.js +4 -7
  210. package/dist/routes/plans/components/ActionPlanPage.js.map +1 -1
  211. package/dist/routes/plans/components/PlanDetailRouteContent.d.ts.map +1 -1
  212. package/dist/routes/plans/components/PlanDetailRouteContent.js +2 -1
  213. package/dist/routes/plans/components/PlanDetailRouteContent.js.map +1 -1
  214. package/dist/routes/rules/hooks/useRuleFactsPreview.js +4 -4
  215. package/dist/routes/rules/hooks/useRuleFactsPreview.js.map +1 -1
  216. package/dist/shacl/form-appearance.d.ts +1 -1
  217. package/dist/shacl/form-appearance.d.ts.map +1 -1
  218. package/dist/shacl/form-appearance.js +1 -1
  219. package/dist/shacl/form-appearance.js.map +1 -1
  220. package/dist/shared/graph-derived-queries.js +2 -2
  221. package/dist/shared/graph-derived-queries.js.map +1 -1
  222. package/package.json +12 -7
  223. package/src/app-subpaths.json +1 -0
  224. package/src/components/channel-icon/index.tsx +1 -1
  225. package/src/components/datastore-management/tree.ts +5 -5
  226. package/src/components/explain-fact/ExplainFact.tsx +3 -3
  227. package/src/components/planning/ActioningView.tsx +62 -70
  228. package/src/components/planning/ManualActionCard.tsx +66 -14
  229. package/src/components/planning/ManualActionList.tsx +30 -11
  230. package/src/components/planning/actioning-view-utils.ts +27 -1
  231. package/src/components/planning/plan-detail-utils.tsx +2 -0
  232. package/src/components/tool-invocation-card/ListRulesResultDisplay.tsx +2 -2
  233. package/src/components/tool-invocation-card/ToolOutputRenderer.tsx +10 -8
  234. package/src/components/tool-invocation-card/types.ts +8 -8
  235. package/src/components/tooltip/index.tsx +35 -2
  236. package/src/explain-fact/rule-presentation.ts +2 -2
  237. package/src/explain-fact/tree-model.ts +2 -2
  238. package/src/graph/entity-link.tsx +20 -0
  239. package/src/graph/graph-list-utils.ts +2 -0
  240. package/src/graph/graph-model.ts +15 -6
  241. package/src/graph/nodes/BrandAssetAnalysisView.tsx +3 -1
  242. package/src/graph/nodes/BrandFontSuggestionView.tsx +7 -1
  243. package/src/graph/nodes/BrandGuidelinesView.tsx +1 -1
  244. package/src/graph/nodes/NodePropertyTable.tsx +32 -143
  245. package/src/graph/nodes/node-property-row.tsx +154 -0
  246. package/src/graph/property-formatters.ts +5 -1
  247. package/src/graph/special-nodes/AttributeList.tsx +177 -0
  248. package/src/graph/special-nodes/EntityPreview.tsx +27 -0
  249. package/src/graph/special-nodes/EntityValueChip.tsx +85 -0
  250. package/src/graph/special-nodes/GenericView.tsx +49 -139
  251. package/src/graph/special-nodes/card-facts.ts +278 -0
  252. package/src/graph/special-nodes/property-icons.ts +59 -0
  253. package/src/graph/status-utils.ts +40 -0
  254. package/src/graph/types.ts +4 -0
  255. package/src/hooks/use-approve-anyway.ts +100 -0
  256. package/src/ldo-ui.ts +8 -0
  257. package/src/lib/find-latest-staged-rule.ts +1 -1
  258. package/src/lib/manual-actions.ts +3 -2
  259. package/src/lib/tool-icons.ts +6 -6
  260. package/src/lib/tool-names.ts +0 -1
  261. package/src/ontology/skolem.ts +2 -2
  262. package/src/providers/ActiveChatProvider.tsx +3 -1
  263. package/src/providers/ChatManagerProvider.tsx +3 -1
  264. package/src/providers/KnowledgeGraphStateProvider.tsx +1 -1
  265. package/src/providers/chat-socket-auth.ts +95 -16
  266. package/src/providers/index.tsx +16 -1
  267. package/src/routes/activity/detail/ActivityChanges.tsx +21 -5
  268. package/src/routes/activity/detail/ActivityDetail.tsx +24 -5
  269. package/src/routes/activity/detail/ActivityStepsRail.tsx +4 -2
  270. package/src/routes/activity/detail/ActivityTimeline.tsx +2 -2
  271. package/src/routes/activity/detail/NoChangesMessage.tsx +20 -0
  272. package/src/routes/data-explorer/class-properties.ts +2 -2
  273. package/src/routes/data-explorer/classes.ts +2 -2
  274. package/src/routes/data-explorer/components/RawTriples.tsx +1 -1
  275. package/src/routes/data-explorer/components/RecentTypes.tsx +1 -1
  276. package/src/routes/data-explorer/components/class-detail/Instances.tsx +1 -1
  277. package/src/routes/data-explorer/components/namespace-detail/NamespaceClassRow.tsx +1 -1
  278. package/src/routes/data-explorer/components/ontology-coverage/CoverageTermColumns.tsx +1 -1
  279. package/src/routes/data-explorer/components/ontology-coverage/UnobservedRuleVocabulary.tsx +1 -1
  280. package/src/routes/data-explorer/components/record-detail/ChatPreview.tsx +2 -2
  281. package/src/routes/data-explorer/recents.ts +1 -1
  282. package/src/routes/data-explorer/shapes.ts +2 -2
  283. package/src/routes/datastores/flatten.ts +1 -1
  284. package/src/routes/integrations/components/connect-forms/CanvaConnectForm.tsx +26 -0
  285. package/src/routes/integrations/components/connect-forms/DataConnectionConnectForm.tsx +38 -12
  286. package/src/routes/integrations/components/connect-forms/data-connection-fields.ts +11 -2
  287. package/src/routes/integrations/connect-forms.ts +1 -0
  288. package/src/routes/integrations/connection-view.ts +1 -0
  289. package/src/routes/integrations/types.ts +2 -0
  290. package/src/routes/plans/components/ActionPlanPage.tsx +9 -8
  291. package/src/routes/plans/components/PlanDetailRouteContent.tsx +4 -3
  292. package/src/routes/rules/hooks/useRuleFactsPreview.ts +4 -4
  293. package/src/shacl/form-appearance.ts +1 -1
  294. package/src/shared/graph-derived-queries.ts +2 -2
  295. package/dist/components/planning/ExecutionActivityRow.d.ts +0 -9
  296. package/dist/components/planning/ExecutionActivityRow.d.ts.map +0 -1
  297. package/dist/components/planning/ExecutionActivityRow.js +0 -53
  298. package/dist/components/planning/ExecutionActivityRow.js.map +0 -1
  299. package/dist/components/planning/ExecutionSectionItem.d.ts +0 -20
  300. package/dist/components/planning/ExecutionSectionItem.d.ts.map +0 -1
  301. package/dist/components/planning/ExecutionSectionItem.js +0 -66
  302. package/dist/components/planning/ExecutionSectionItem.js.map +0 -1
  303. package/dist/components/planning/ExecutionSections.d.ts +0 -16
  304. package/dist/components/planning/ExecutionSections.d.ts.map +0 -1
  305. package/dist/components/planning/ExecutionSections.js +0 -32
  306. package/dist/components/planning/ExecutionSections.js.map +0 -1
  307. package/dist/components/planning/action-plan-icons.d.ts +0 -3
  308. package/dist/components/planning/action-plan-icons.d.ts.map +0 -1
  309. package/dist/components/planning/action-plan-icons.js +0 -25
  310. package/dist/components/planning/action-plan-icons.js.map +0 -1
  311. package/dist/components/planning/execution-section-model.d.ts +0 -24
  312. package/dist/components/planning/execution-section-model.d.ts.map +0 -1
  313. package/dist/components/planning/execution-section-model.js +0 -150
  314. package/dist/components/planning/execution-section-model.js.map +0 -1
  315. package/dist/routes/data-explorer/components/TruncateTooltip.d.ts +0 -7
  316. package/dist/routes/data-explorer/components/TruncateTooltip.d.ts.map +0 -1
  317. package/dist/routes/data-explorer/components/TruncateTooltip.js +0 -9
  318. package/dist/routes/data-explorer/components/TruncateTooltip.js.map +0 -1
  319. package/src/components/planning/ExecutionActivityRow.tsx +0 -89
  320. package/src/components/planning/ExecutionSectionItem.tsx +0 -184
  321. package/src/components/planning/ExecutionSections.tsx +0 -97
  322. package/src/components/planning/action-plan-icons.tsx +0 -27
  323. package/src/components/planning/execution-section-model.ts +0 -190
  324. package/src/routes/data-explorer/components/TruncateTooltip.tsx +0 -25
@@ -1,47 +1,24 @@
1
- import { isPresent } from "@manta-eu/lib/present";
2
- import { expandPrefix } from "@manta-eu/rdf-lib/namespaces";
3
1
  import { ChevronRight } from "lucide-react";
4
2
  import { memo, useCallback, useMemo } from "react";
5
- import {
6
- getCurrencyCode,
7
- isDisplayablePreviewKey,
8
- selectPriorityPreviewFields,
9
- type PreviewFieldHints,
10
- } from "../graph-list-utils";
11
- import { ontologyTermIrisForProperties, withOntologyLabels } from "../ontology-labels";
12
- import { rdfTypeColors } from "../rdf-type-colors";
13
- import { statusColors } from "../status-utils";
14
- import { useGraphTheme } from "../themes";
15
- import type { EntityViewProps } from "../types";
3
+ import type { PreviewFieldHints } from "../graph-list-utils";
4
+ import { statusBadgeVariant } from "../status-utils";
5
+ import type { EntityViewProps, NodeProperty } from "../types";
6
+ import { AttributeList, useAttributeFacts } from "./AttributeList";
7
+ import { typeColor } from "./card-facts";
16
8
  import { getStatus } from "./node-data";
17
- import { useOntologyTerms } from "#hooks/use-ontology-terms";
9
+ import { Badge } from "#components/badge/index";
18
10
  import { cn } from "#style";
19
11
 
20
- const defaultColor = "#6b7280";
21
- const explainCardMaxFacts = 5;
22
-
23
- type CardFact = { label: string; value: string; highlighted: boolean };
24
-
25
- function getNodeColor(type?: string): string {
26
- if (!type) return defaultColor;
27
- return rdfTypeColors[type] ?? rdfTypeColors[expandPrefix(type)] ?? defaultColor;
28
- }
29
-
30
- function getStatusStyle(status: string): { bg: string; text: string } {
31
- return statusColors[status.toLowerCase()] ?? { bg: "#94a3b8", text: "#ffffff" };
32
- }
33
-
34
12
  export type GenericViewProps = EntityViewProps & {
35
13
  previewHints?: PreviewFieldHints;
36
14
  onToggleCollapse?: () => void;
15
+ defaultExpanded?: boolean;
37
16
  };
38
17
 
39
18
  export const GenericView = memo(function GenericView(props: GenericViewProps) {
40
- const { data, selected = false, onContextMenu, previewHints, onToggleCollapse } = props;
41
-
42
- const theme = useGraphTheme();
19
+ const { data, selected = false, onContextMenu, previewHints, onToggleCollapse, defaultExpanded } = props;
43
20
 
44
- const color = useMemo(() => getNodeColor(data.type), [data.type]);
21
+ const color = useMemo(() => typeColor(data.type), [data.type]);
45
22
  const hasChildren = data.hasChildren;
46
23
  const isCollapsed = data.isCollapsed;
47
24
 
@@ -55,137 +32,70 @@ export const GenericView = memo(function GenericView(props: GenericViewProps) {
55
32
 
56
33
  const status = useMemo(() => getStatus(data), [data]);
57
34
 
58
- const ontologyTerms = useOntologyTerms(
59
- useMemo(() => ontologyTermIrisForProperties(data.properties), [data.properties]),
60
- );
61
-
62
- const labeledProperties = useMemo(
63
- () => withOntologyLabels(data.properties, ontologyTerms),
64
- [data.properties, ontologyTerms],
65
- );
66
-
67
- const { displayProperties, hiddenPropertiesCount } = useMemo(() => {
68
- const properties = status ? labeledProperties.filter((prop) => prop.key !== status.key) : labeledProperties;
69
-
70
- if (previewHints) {
71
- const fields = selectPriorityPreviewFields(properties, previewHints, getCurrencyCode([], properties), {
72
- limit: explainCardMaxFacts,
73
- keepUnmatched: true,
74
- });
75
-
76
- const total = properties.filter((prop) => isDisplayablePreviewKey(prop.key)).length;
77
-
78
- const facts: CardFact[] = fields.map((field) => ({
79
- label: field.label,
80
- value: field.value,
81
- highlighted: field.isHighlighted ?? false,
82
- }));
83
-
84
- return { displayProperties: facts, hiddenPropertiesCount: Math.max(0, total - facts.length) };
85
- }
86
-
87
- const importantKeys = ["name", "title", "label", "description", "id"];
88
- const important: typeof properties = [];
89
- const other: typeof properties = [];
90
-
91
- for (const prop of properties) {
92
- const keyLower = prop.key.toLowerCase();
93
- if (importantKeys.some((k) => keyLower.includes(k))) {
94
- important.push(prop);
95
- } else {
96
- other.push(prop);
97
- }
98
- }
99
-
100
- const maxProperties = 4;
101
- const allDisplayed: CardFact[] = [...important, ...other]
102
- .slice(0, maxProperties)
103
- .map((prop) => ({ label: prop.label ?? prop.key, value: prop.value, highlighted: false }));
104
-
105
- return {
106
- displayProperties: allDisplayed,
107
- hiddenPropertiesCount: Math.max(0, important.length + other.length - maxProperties),
108
- };
109
- }, [labeledProperties, status, previewHints]);
35
+ const include = useCallback((property: NodeProperty) => !status || property.key !== status.key, [status]);
36
+ // The header badge shows the status, so an IRI-valued one must not come back as a relation row either.
37
+ const relations = useMemo(() => {
38
+ const statusIri = status ? data.properties.find((property) => property.key === status.key)?.iri : undefined;
39
+ return statusIri ? data.relations?.filter((relation) => relation.predicate !== statusIri) : data.relations;
40
+ }, [status, data.properties, data.relations]);
41
+
42
+ const { facts, previewCount } = useAttributeFacts({
43
+ properties: data.properties,
44
+ relations,
45
+ jsonLd: data.jsonLd,
46
+ title: data.label,
47
+ type: data.type,
48
+ prefixLabels: true,
49
+ previewHints,
50
+ include,
51
+ });
110
52
 
111
53
  return (
112
54
  <div
113
- className="rounded-lg shadow-md min-w-60 max-w-80 transition-all duration-200 overflow-hidden"
114
- style={{
115
- backgroundColor: theme.node.background,
116
- borderColor: color,
117
- borderWidth: 2,
118
- borderStyle: "solid",
119
- ...(selected && { boxShadow: `0 0 0 2px ${theme.node.selectedRing}` }),
120
- }}
55
+ className={cn(
56
+ "min-w-60 max-w-80 overflow-hidden rounded-md-v4 border border-muted-border bg-muted text-default-foreground transition-shadow duration-200",
57
+ selected && "ring-2 ring-active-border",
58
+ )}
121
59
  onContextMenu={onContextMenu}
122
60
  >
123
- <div className="px-3 py-2 flex items-center justify-between gap-2" style={{ backgroundColor: `${color}20` }}>
124
- <div className="flex items-center gap-2 min-w-0">
61
+ <div className="flex items-center justify-between gap-2 border-b border-muted-border px-3 py-2">
62
+ <div className="flex min-w-0 items-center gap-2">
125
63
  {hasChildren && onToggleCollapse && (
126
64
  <button
65
+ type="button"
127
66
  onClick={handleToggleClick}
128
- className={cn(
129
- "w-5 h-5 rounded flex items-center justify-center shrink-0",
130
- "bg-muted",
131
- "hover:bg-muted transition-all duration-200",
132
- )}
133
- style={{ color: theme.node.text }}
67
+ className="nodrag flex size-5 shrink-0 items-center justify-center rounded bg-accent text-muted-foreground transition-colors hover:text-default-foreground"
134
68
  title={isCollapsed ? "Expand" : "Collapse"}
135
69
  >
136
- <ChevronRight className={cn("w-3 h-3 transition-transform duration-200", !isCollapsed && "rotate-90")} />
70
+ <ChevronRight className={cn("size-3 transition-transform duration-200", !isCollapsed && "rotate-90")} />
137
71
  </button>
138
72
  )}
139
- <div className="typography-small truncate" style={{ color: theme.node.text }} title={data.label}>
73
+ <span aria-hidden className="size-2 shrink-0 rounded-full" style={{ backgroundColor: color }} />
74
+ <div className="typography-small-medium truncate" title={data.label}>
140
75
  {data.label}
141
76
  </div>
142
77
  </div>
143
- <div className="flex items-center gap-1.5 shrink-0">
78
+ <div className="flex shrink-0 items-center gap-1.5">
144
79
  {status && (
145
- <span
146
- className="px-1.5 py-0.5 rounded typography-tiny"
147
- style={{ backgroundColor: getStatusStyle(status.value).bg, color: getStatusStyle(status.value).text }}
148
- >
80
+ <Badge size="sm" variant={statusBadgeVariant(status.value)}>
149
81
  {status.value.toLowerCase()}
150
- </span>
82
+ </Badge>
151
83
  )}
152
84
  {hasChildren && isCollapsed && (
153
- <span
154
- className="px-1.5 py-0.5 rounded typography-tiny text-primary-foreground"
155
- style={{ backgroundColor: color }}
156
- >
85
+ <Badge size="sm" variant="secondary">
157
86
  +{data.childIds.length}
158
- </span>
87
+ </Badge>
159
88
  )}
160
89
  </div>
161
90
  </div>
162
91
 
163
- {isPresent(displayProperties) && (
164
- <div className="px-3 py-2 space-y-1">
165
- {displayProperties.map(({ label, value, highlighted }, index) => (
166
- <div key={index} className="flex justify-between typography-tiny gap-2">
167
- <span style={{ color: theme.node.textMuted }} className="shrink-0">
168
- {label}:
169
- </span>
170
- <span
171
- style={{
172
- color: highlighted ? theme.node.selectedRing : theme.node.text,
173
- fontWeight: highlighted ? 600 : undefined,
174
- }}
175
- className="truncate text-right tabular-nums"
176
- title={value}
177
- >
178
- {value}
179
- </span>
180
- </div>
181
- ))}
182
- {hiddenPropertiesCount > 0 && (
183
- <div className="typography-tiny italic" style={{ color: theme.node.textMuted }}>
184
- +{hiddenPropertiesCount} more
185
- </div>
186
- )}
187
- </div>
188
- )}
92
+ <AttributeList
93
+ facts={facts}
94
+ previewCount={previewCount}
95
+ defaultExpanded={defaultExpanded}
96
+ searchClassName="px-3"
97
+ bodyClassName="px-3 py-2"
98
+ />
189
99
  </div>
190
100
  );
191
101
  });
@@ -0,0 +1,278 @@
1
+ import { isFullIri } from "@manta-eu/client/shared/rdf-namespaces";
2
+ import { isPresent } from "@manta-eu/lib/present";
3
+ import { compactUri, expandPrefix } from "@manta-eu/rdf-lib/namespaces";
4
+ import type { LucideIcon } from "lucide-react";
5
+ import { groupBy, isNotNil, uniq } from "ramda";
6
+ import {
7
+ getCurrencyCode,
8
+ isDisplayablePreviewKey,
9
+ normalizePredicateKey,
10
+ selectPriorityPreviewFields,
11
+ type PreviewFieldHints,
12
+ } from "../graph-list-utils";
13
+ import { classifyPropertyDisplay, type PropertyDisplay } from "../nodes/node-property-display";
14
+ import { ontologyPropertyIri } from "../ontology-labels";
15
+ import { formatDisplayValue, isIsoDateTime, parseNumeric } from "../property-formatters";
16
+ import { rdfTypeColors } from "../rdf-type-colors";
17
+ import type { NodeProperty, NodeRelation } from "../types";
18
+ import { getChannelFromId } from "./node-data";
19
+ import { propertyIcon, relationIcon } from "./property-icons";
20
+ import type { Channel } from "#components/channel-icon/index";
21
+ import { formatPropertyLabel } from "#lib/iri-labels";
22
+ import type { OntologyTerm } from "#lib/ontology-terms";
23
+ import { searchItems } from "#lib/search";
24
+
25
+ export const explainCardMaxFacts = 5;
26
+ export const defaultCardMaxFacts = 4;
27
+ export const attributeSearchThreshold = 8;
28
+ export const collapsedChipLimit = 3;
29
+
30
+ const defaultColor = "#6b7280";
31
+ const importantKeys = new Set(["name", "title", "label", "description", "id", "identifier"]);
32
+
33
+ export type CardFact = {
34
+ key: string;
35
+ predicate?: string;
36
+ label: string;
37
+ value: string;
38
+ display: PropertyDisplay;
39
+ icon: LucideIcon;
40
+ entityIris: string[];
41
+ entityColor?: string;
42
+ highlighted: boolean;
43
+ channel?: Channel;
44
+ };
45
+
46
+ export function typeColor(type?: string): string {
47
+ if (!type) return defaultColor;
48
+ return rdfTypeColors[type] ?? rdfTypeColors[expandPrefix(type)] ?? defaultColor;
49
+ }
50
+
51
+ // Only numbers and timestamps are reformatted; text such as "FR" stays as stored.
52
+ export function formatFactValue(property: NodeProperty): string {
53
+ if (parseNumeric(property.value) === null && !isIsoDateTime(property.value)) return property.value;
54
+
55
+ return formatDisplayValue(property.value, {
56
+ predicate: property.iri ?? property.key,
57
+ predicateLabel: property.label ?? property.key,
58
+ valueScale: property.valueScale,
59
+ });
60
+ }
61
+
62
+ function looksRaw(label: string): boolean {
63
+ return !/\s/.test(label) && (/^[a-z]/.test(label) || /[a-z][A-Z]/.test(label) || /[:/#]/.test(label));
64
+ }
65
+
66
+ export function readableLabel(property: NodeProperty): string {
67
+ const raw = property.label || property.iri || property.key;
68
+
69
+ // Only a raw property name or IRI is re-cased; a real label like "ROAS" stays as written.
70
+ return looksRaw(raw) ? formatPropertyLabel(raw) : raw;
71
+ }
72
+
73
+ export function iriChannel(iri: string | undefined): Channel | undefined {
74
+ return iri ? getChannelFromId(compactUri(iri)) : undefined;
75
+ }
76
+
77
+ function vocabularyPrefix(iri: string): string | undefined {
78
+ const compact = compactUri(iri);
79
+ return compact === iri ? undefined : /^([A-Za-z][\w-]*):/.exec(compact)?.[1];
80
+ }
81
+
82
+ // A platform with a logo shows it next to the label; another vocabulary than schema.org or the card's own type
83
+ // keeps its prefix as text.
84
+ export function sourcedLabel(label: string, predicate: string | undefined, type?: string): string {
85
+ if (!predicate || isPresent(iriChannel(predicate))) return label;
86
+
87
+ const prefix = vocabularyPrefix(predicate);
88
+ if (!prefix || prefix === "schema" || (type && prefix === vocabularyPrefix(expandPrefix(type)))) return label;
89
+
90
+ return `${prefix.charAt(0).toUpperCase()}${prefix.slice(1)}:${label}`;
91
+ }
92
+
93
+ type LabelSource = (label: string, predicate: string | undefined) => string;
94
+
95
+ const plainLabel: LabelSource = (label) => label;
96
+
97
+ function termFor(terms: Map<string, OntologyTerm>, predicate: string | undefined): OntologyTerm | undefined {
98
+ const iri = ontologyPropertyIri(predicate);
99
+ return iri ? terms.get(iri) : undefined;
100
+ }
101
+
102
+ // Whole words, so "confidence" or "width" never pass for an "id".
103
+ export function keyWords(key: string): string[] {
104
+ return key
105
+ .split(/[^A-Za-z0-9]+|(?<=[a-z0-9])(?=[A-Z])/)
106
+ .filter(Boolean)
107
+ .map((word) => word.toLowerCase());
108
+ }
109
+
110
+ export function relationFacts(
111
+ relations: NodeRelation[],
112
+ terms: Map<string, OntologyTerm>,
113
+ labelFor: LabelSource = plainLabel,
114
+ ): CardFact[] {
115
+ const byPredicate = groupBy(
116
+ (relation: NodeRelation) => relation.predicate,
117
+ relations.filter((relation) => isFullIri(relation.target)),
118
+ );
119
+
120
+ return Object.entries(byPredicate).map(([predicate, group]) => {
121
+ const targets = uniq((group ?? []).map((relation) => relation.target));
122
+ const term = termFor(terms, predicate);
123
+ const range = term?.rangeIncludes[0];
124
+ const allOntologyTerms = targets.every((target) => isPresent(termFor(terms, target)?.label));
125
+
126
+ return {
127
+ key: `${predicate} entities`,
128
+ predicate,
129
+ label: labelFor(readableLabel({ key: predicate, value: "", iri: predicate, label: term?.label }), predicate),
130
+ value: targets.join(", "),
131
+ display: { kind: "text", text: targets.join(", ") },
132
+ icon: allOntologyTerms ? propertyIcon({ range, display: { kind: "text", text: "" } }) : relationIcon(range),
133
+ entityIris: targets,
134
+ entityColor: typeColor(range),
135
+ highlighted: false,
136
+ channel: iriChannel(predicate),
137
+ };
138
+ });
139
+ }
140
+
141
+ function propertyFact(
142
+ property: NodeProperty,
143
+ jsonLd: Record<string, unknown>,
144
+ terms: Map<string, OntologyTerm>,
145
+ labelFor: LabelSource,
146
+ ) {
147
+ const label = readableLabel(property);
148
+ const value = formatFactValue(property);
149
+ const raw = jsonLd[property.iri ?? ""] ?? property.value;
150
+ const display = classifyPropertyDisplay({ label, formatted: value, raw });
151
+ const range = termFor(terms, property.iri)?.rangeIncludes[0];
152
+
153
+ return {
154
+ key: property.iri ?? property.key,
155
+ label: labelFor(label, property.iri),
156
+ value,
157
+ display,
158
+ icon: propertyIcon({ range, display, isDate: isIsoDateTime(property.value) }),
159
+ entityIris: [],
160
+ highlighted: false,
161
+ channel: iriChannel(property.iri),
162
+ } satisfies CardFact;
163
+ }
164
+
165
+ // graph-model records each IRI value as a relation, rendered as a chip; the property keeps only its other values.
166
+ function withoutRelationValues(
167
+ property: NodeProperty,
168
+ relations: NodeRelation[],
169
+ jsonLd: Record<string, unknown>,
170
+ ): NodeProperty[] {
171
+ const targets = new Set(
172
+ relations.filter((relation) => relation.predicate === property.iri).map((relation) => relation.target),
173
+ );
174
+ if (targets.size === 0) return [property];
175
+
176
+ const raw = jsonLd[property.iri ?? ""];
177
+ const values = (Array.isArray(raw) ? raw : [raw]).filter(
178
+ (value): value is string | number | boolean => isNotNil(value) && typeof value !== "object",
179
+ );
180
+ const rest = values.map(String).filter((value) => !targets.has(value));
181
+
182
+ return isPresent(rest) ? [{ ...property, value: rest.join(" | ") }] : [];
183
+ }
184
+
185
+ export type BuildCardFactsArgs = {
186
+ properties: NodeProperty[];
187
+ relations: NodeRelation[];
188
+ jsonLd: Record<string, unknown>;
189
+ terms: Map<string, OntologyTerm>;
190
+ title?: string;
191
+ type?: string;
192
+ // Only the fallback card names a foreign vocabulary; typed cards keep their labels as written.
193
+ prefixLabels?: boolean;
194
+ previewHints?: PreviewFieldHints;
195
+ };
196
+
197
+ export function buildCardFacts(args: BuildCardFactsArgs): { facts: CardFact[]; previewCount: number } {
198
+ const { relations, jsonLd, terms, title, type, prefixLabels = false, previewHints } = args;
199
+ const labelFor: LabelSource = prefixLabels ? (label, predicate) => sourcedLabel(label, predicate, type) : plainLabel;
200
+
201
+ const properties = args.properties.flatMap((property) => withoutRelationValues(property, relations, jsonLd));
202
+ const linkedFacts = relationFacts(relations, terms, labelFor);
203
+ function notTitle(fact: CardFact) {
204
+ return title === undefined || fact.value !== title;
205
+ }
206
+
207
+ if (previewHints) {
208
+ const displayable = properties
209
+ .filter((property) => isDisplayablePreviewKey(property.key))
210
+ .map((property) => ({ ...property, label: readableLabel(property) }));
211
+ const fields = selectPriorityPreviewFields(displayable, previewHints, getCurrencyCode([], properties), {
212
+ limit: displayable.length,
213
+ keepUnmatched: true,
214
+ });
215
+
216
+ const explainFacts = fields.map((field): CardFact => {
217
+ const display = classifyPropertyDisplay({ label: field.label, formatted: field.value, raw: field.rawValue });
218
+
219
+ return {
220
+ key: field.id,
221
+ label: labelFor(field.label, field.predicate),
222
+ value: field.value,
223
+ display,
224
+ icon: propertyIcon({ display, isDate: isIsoDateTime(field.rawValue ?? "") }),
225
+ entityIris: [],
226
+ highlighted: field.isHighlighted ?? false,
227
+ channel: iriChannel(field.predicate),
228
+ };
229
+ });
230
+
231
+ const highlight = previewHints.highlightPredicate
232
+ ? normalizePredicateKey(previewHints.highlightPredicate)
233
+ : undefined;
234
+ function isHighlighted(fact: CardFact) {
235
+ return isPresent(highlight) && isPresent(fact.predicate) && normalizePredicateKey(fact.predicate) === highlight;
236
+ }
237
+ const linked = linkedFacts.map((fact) => (isHighlighted(fact) ? { ...fact, highlighted: true } : fact));
238
+
239
+ return {
240
+ facts: [
241
+ ...linked.filter(isHighlighted),
242
+ ...explainFacts,
243
+ ...linked.filter((fact) => !isHighlighted(fact)),
244
+ ].filter(notTitle),
245
+ previewCount: explainCardMaxFacts,
246
+ };
247
+ }
248
+
249
+ function isImportant(property: NodeProperty) {
250
+ return keyWords(property.key).some((word) => importantKeys.has(word));
251
+ }
252
+ const important = properties.filter(isImportant).map((property) => propertyFact(property, jsonLd, terms, labelFor));
253
+ const other = properties
254
+ .filter((property) => !isImportant(property))
255
+ .map((property) => propertyFact(property, jsonLd, terms, labelFor));
256
+
257
+ return { facts: [...important, ...linkedFacts, ...other].filter(notTitle), previewCount: defaultCardMaxFacts };
258
+ }
259
+
260
+ export function isAttributeSearchable(expanded: boolean, factCount: number): boolean {
261
+ return expanded && factCount > attributeSearchThreshold;
262
+ }
263
+
264
+ export function visibleChips(iris: string[], expanded: boolean): { shown: string[]; hiddenCount: number } {
265
+ const shown = expanded ? iris : iris.slice(0, collapsedChipLimit);
266
+
267
+ return { shown, hiddenCount: iris.length - shown.length };
268
+ }
269
+
270
+ // A linked-entity row is found by its label: its value is the targets' IRIs, which say nothing a reader sees.
271
+ export function searchFacts(facts: CardFact[], query: string): CardFact[] {
272
+ const documents = facts.map((fact) => ({
273
+ fact,
274
+ text: isPresent(fact.entityIris) ? fact.label : `${fact.label} ${fact.value}`,
275
+ }));
276
+
277
+ return searchItems(documents, query, { keys: ["text"], threshold: 0.35 }).map((document) => document.fact);
278
+ }
@@ -0,0 +1,59 @@
1
+ import { RangeKind, rangeKind } from "@manta-eu/ldo/range-kinds";
2
+ import { expandPrefix } from "@manta-eu/rdf-lib/namespaces";
3
+ import {
4
+ AlignLeft,
5
+ Building2,
6
+ Calendar,
7
+ CircleDollarSign,
8
+ Hash,
9
+ Link2,
10
+ type LucideIcon,
11
+ Palette,
12
+ Percent,
13
+ Tags,
14
+ ToggleLeft,
15
+ Type,
16
+ User,
17
+ } from "lucide-react";
18
+ import { match } from "ts-pattern";
19
+ import type { PropertyDisplay } from "../nodes/node-property-display";
20
+
21
+ const kindIcons: Record<RangeKind, LucideIcon> = {
22
+ [RangeKind.Text]: Type,
23
+ [RangeKind.Number]: Hash,
24
+ [RangeKind.Boolean]: ToggleLeft,
25
+ [RangeKind.Date]: Calendar,
26
+ [RangeKind.Url]: Link2,
27
+ [RangeKind.Money]: CircleDollarSign,
28
+ [RangeKind.Person]: User,
29
+ [RangeKind.Organization]: Building2,
30
+ };
31
+
32
+ function displayIcon(display: PropertyDisplay): LucideIcon {
33
+ return match(display)
34
+ .with({ kind: "number" }, () => Hash)
35
+ .with({ kind: "boolean" }, () => ToggleLeft)
36
+ .with({ kind: "color" }, () => Palette)
37
+ .with({ kind: "ratio" }, () => Percent)
38
+ .with({ kind: "tags" }, () => Tags)
39
+ .with({ kind: "prose" }, () => AlignLeft)
40
+ .with({ kind: "text" }, () => Type)
41
+ .exhaustive();
42
+ }
43
+
44
+ export function propertyIcon(args: { range?: string; display?: PropertyDisplay; isDate?: boolean }): LucideIcon {
45
+ const { range, display, isDate = false } = args;
46
+
47
+ const kind = range ? rangeKind(expandPrefix(range)) : undefined;
48
+ if (kind) return kindIcons[kind];
49
+
50
+ if (isDate) return Calendar;
51
+
52
+ return display ? displayIcon(display) : Type;
53
+ }
54
+
55
+ export function relationIcon(range?: string): LucideIcon {
56
+ const kind = range ? rangeKind(expandPrefix(range)) : undefined;
57
+
58
+ return kind === RangeKind.Person || kind === RangeKind.Organization ? kindIcons[kind] : Link2;
59
+ }
@@ -1,4 +1,5 @@
1
1
  import type { NodeProperty } from "./types";
2
+ import type { BadgeVariant } from "#components/badge/index";
2
3
 
3
4
  export function titleCase(s: string): string {
4
5
  return s.replace(/\b\w/g, (c) => c.toUpperCase());
@@ -18,6 +19,45 @@ export const statusColors: Record<string, { bg: string; text: string }> = {
18
19
  deleted: { bg: "#ef4444", text: "#ffffff" },
19
20
  };
20
21
 
22
+ export enum NodeStatus {
23
+ Active = "active",
24
+ Enabled = "enabled",
25
+ Serving = "serving",
26
+ Paused = "paused",
27
+ Pending = "pending",
28
+ Draft = "draft",
29
+ Archived = "archived",
30
+ Disabled = "disabled",
31
+ Removed = "removed",
32
+ Error = "error",
33
+ Deleted = "deleted",
34
+ }
35
+
36
+ const knownStatuses: ReadonlySet<string> = new Set(Object.values(NodeStatus));
37
+
38
+ export function isNodeStatus(value: string): value is NodeStatus {
39
+ return knownStatuses.has(value);
40
+ }
41
+
42
+ const statusBadgeVariants: Record<NodeStatus, BadgeVariant> = {
43
+ [NodeStatus.Active]: "success",
44
+ [NodeStatus.Serving]: "success",
45
+ [NodeStatus.Enabled]: "copy",
46
+ [NodeStatus.Draft]: "copy",
47
+ [NodeStatus.Paused]: "warning",
48
+ [NodeStatus.Pending]: "warning",
49
+ [NodeStatus.Archived]: "copy",
50
+ [NodeStatus.Disabled]: "copy",
51
+ [NodeStatus.Removed]: "destructive",
52
+ [NodeStatus.Error]: "destructive",
53
+ [NodeStatus.Deleted]: "destructive",
54
+ };
55
+
56
+ export function statusBadgeVariant(status: string): BadgeVariant {
57
+ const normalized = status.trim().toLowerCase();
58
+ return isNodeStatus(normalized) ? statusBadgeVariants[normalized] : "copy";
59
+ }
60
+
21
61
  export function getStatusFromProperties(properties: NodeProperty[]): string | undefined {
22
62
  return properties.find((p) => {
23
63
  const key = p.key.toLowerCase().trim();
@@ -10,6 +10,9 @@ export type NodeProperty = {
10
10
  valueScale?: number;
11
11
  };
12
12
 
13
+ // A property whose value is another entity in the graph; the canvas draws it as an edge instead.
14
+ export type NodeRelation = { predicate: string; target: string };
15
+
13
16
  export type RDFNodeData = {
14
17
  label: string;
15
18
  type?: string;
@@ -17,6 +20,7 @@ export type RDFNodeData = {
17
20
  isHub: boolean;
18
21
  jsonLd: Record<string, unknown>;
19
22
  properties: NodeProperty[];
23
+ relations?: NodeRelation[];
20
24
  childIds: string[];
21
25
  parentId?: string;
22
26
  isCollapsed: boolean;