pkgviz 0.7.6 → 0.8.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 (367) hide show
  1. package/.next/BUILD_ID +1 -1
  2. package/.next/app-path-routes-manifest.json +2 -1
  3. package/.next/build-manifest.json +15 -24
  4. package/.next/fallback-build-manifest.json +15 -0
  5. package/.next/images-manifest.json +14 -3
  6. package/.next/next-minimal-server.js.nft.json +1 -1
  7. package/.next/next-server.js.nft.json +1 -1
  8. package/.next/prerender-manifest.json +52 -16
  9. package/.next/required-server-files.js +349 -0
  10. package/.next/required-server-files.json +106 -75
  11. package/.next/routes-manifest.json +16 -6
  12. package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
  13. package/.next/server/app/_global-error/page/build-manifest.json +20 -0
  14. package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
  15. package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
  16. package/.next/server/app/_global-error/page.js +9 -0
  17. package/.next/server/app/_global-error/page.js.map +5 -0
  18. package/.next/server/app/_global-error/page.js.nft.json +1 -0
  19. package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
  20. package/.next/server/app/_global-error.html +1 -0
  21. package/.next/server/app/_global-error.meta +22 -0
  22. package/.next/server/app/_global-error.rsc +15 -0
  23. package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +20 -0
  24. package/.next/server/app/_global-error.segments/_full.segment.rsc +15 -0
  25. package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
  26. package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
  27. package/.next/server/app/_not-found/page/build-manifest.json +20 -0
  28. package/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
  29. package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
  30. package/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
  31. package/.next/server/app/_not-found/page.js +13 -2
  32. package/.next/server/app/_not-found/page.js.map +5 -0
  33. package/.next/server/app/_not-found/page.js.nft.json +1 -1
  34. package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -1
  35. package/.next/server/app/_not-found.html +1 -1
  36. package/.next/server/app/_not-found.meta +19 -0
  37. package/.next/server/app/_not-found.rsc +18 -19
  38. package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -0
  39. package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +24 -0
  40. package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
  41. package/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
  42. package/.next/server/app/favicon.ico/route/build-manifest.json +12 -0
  43. package/.next/server/app/favicon.ico/route.js +6 -1
  44. package/.next/server/app/favicon.ico/route.js.map +5 -0
  45. package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
  46. package/.next/server/app/page/app-paths-manifest.json +3 -0
  47. package/.next/server/app/page/build-manifest.json +20 -0
  48. package/.next/server/app/page/next-font-manifest.json +11 -0
  49. package/.next/server/app/page/react-loadable-manifest.json +1 -0
  50. package/.next/server/app/page/server-reference-manifest.json +93 -0
  51. package/.next/server/app/page.js +16 -13
  52. package/.next/server/app/page.js.map +5 -0
  53. package/.next/server/app/page.js.nft.json +1 -1
  54. package/.next/server/app/page_client-reference-manifest.js +3 -1
  55. package/.next/server/app-paths-manifest.json +2 -1
  56. package/.next/server/chunks/[externals]__0l8ei7u._.js +3 -0
  57. package/.next/server/chunks/[externals]__0l8ei7u._.js.map +1 -0
  58. package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js +160 -0
  59. package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js.map +1 -0
  60. package/.next/server/chunks/[turbopack]_runtime.js +807 -0
  61. package/.next/server/chunks/[turbopack]_runtime.js.map +10 -0
  62. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js +3 -0
  63. package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js.map +1 -0
  64. package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js +28 -0
  65. package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js.map +1 -0
  66. package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js +33 -0
  67. package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js.map +1 -0
  68. package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js +3 -0
  69. package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js.map +1 -0
  70. package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js +14 -0
  71. package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js.map +1 -0
  72. package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js +3 -0
  73. package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js.map +1 -0
  74. package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js +3 -0
  75. package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js.map +1 -0
  76. package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js +3 -0
  77. package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js.map +1 -0
  78. package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js +33 -0
  79. package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js.map +1 -0
  80. package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js +3 -0
  81. package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js.map +1 -0
  82. package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js +3 -0
  83. package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js.map +1 -0
  84. package/.next/server/chunks/ssr/[turbopack]_runtime.js +807 -0
  85. package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +10 -0
  86. package/.next/server/chunks/ssr/_1acy_2s._.js +158 -0
  87. package/.next/server/chunks/ssr/_1acy_2s._.js.map +1 -0
  88. package/.next/server/chunks/ssr/_1rh2tf9._.js +367 -0
  89. package/.next/server/chunks/ssr/_1rh2tf9._.js.map +1 -0
  90. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js +3 -0
  91. package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js.map +1 -0
  92. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js +3 -0
  93. package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js.map +1 -0
  94. package/.next/server/chunks/ssr/node_modules_01xbj_9._.js +33 -0
  95. package/.next/server/chunks/ssr/node_modules_01xbj_9._.js.map +1 -0
  96. package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js +3 -0
  97. package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js.map +1 -0
  98. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +6 -0
  99. package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js.map +1 -0
  100. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js +3 -0
  101. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js.map +1 -0
  102. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js +3 -0
  103. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js.map +1 -0
  104. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js +3 -0
  105. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js.map +1 -0
  106. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js +3 -0
  107. package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js.map +1 -0
  108. package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js +3 -0
  109. package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js.map +1 -0
  110. package/.next/server/middleware-build-manifest.js +24 -1
  111. package/.next/server/middleware-manifest.json +2 -2
  112. package/.next/server/next-font-manifest.js +1 -1
  113. package/.next/server/next-font-manifest.json +15 -1
  114. package/.next/server/pages/404.html +1 -1
  115. package/.next/server/pages/500.html +1 -1
  116. package/.next/server/pages-manifest.json +2 -4
  117. package/.next/server/prefetch-hints.json +25 -0
  118. package/.next/server/server-reference-manifest.js +1 -1
  119. package/.next/server/server-reference-manifest.json +94 -1
  120. package/.next/static/chunks/19mx3mg6lkumu.js +1 -0
  121. package/.next/static/chunks/1las_6j17xa9p.js +1 -0
  122. package/.next/static/chunks/1xk6snnh6e5_j.css +3 -0
  123. package/.next/static/chunks/2-rtuqsgzmno4.js +22 -0
  124. package/.next/static/chunks/27t_qfc-3_lzs.js +1 -0
  125. package/.next/static/chunks/2sswp23h6zh08.js +345 -0
  126. package/.next/static/chunks/310vm2bl3xxpt.js +31 -0
  127. package/.next/static/chunks/3fntmmi971322.js +1 -0
  128. package/.next/static/chunks/turbopack-1b6uko1cu_h42.js +1 -0
  129. package/.next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
  130. package/.next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
  131. package/.next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
  132. package/.next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
  133. package/.next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
  134. package/.next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
  135. package/.next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
  136. package/.next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
  137. package/.next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
  138. package/.next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
  139. package/.next/static/media/favicon.2246eezznj2ab.ico +0 -0
  140. package/.next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
  141. package/.next/static/rjdzHqzPw2GCNhDbjcu0-/_buildManifest.js +11 -0
  142. package/.next/static/rjdzHqzPw2GCNhDbjcu0-/_clientMiddlewareManifest.js +1 -0
  143. package/README.md +176 -4
  144. package/bin/pkgviz.ts +57 -29
  145. package/package.json +57 -36
  146. package/src/app/actions/audit.actions.ts +7 -49
  147. package/src/app/globals.css +0 -2
  148. package/src/app/layout.tsx +3 -2
  149. package/src/app/loading.tsx +8 -0
  150. package/src/app/page.tsx +16 -2
  151. package/src/app/utils/buildGraph.ts +99 -100
  152. package/src/app/utils/getParsedFileStructure.ts +128 -54
  153. package/src/app/utils/inspectParserLanguageAsync.ts +39 -0
  154. package/src/app/utils/markCyclicPackages.ts +45 -185
  155. package/src/app/utils/parser/cpp/parseCppFile.ts +68 -86
  156. package/src/app/utils/parser/delphi/parseFile.ts +36 -120
  157. package/src/app/utils/parser/java/findEntryPoint.ts +2 -1
  158. package/src/app/utils/parser/java/parseJavaFile.ts +33 -45
  159. package/src/app/utils/parser/kotlin/parseFile.ts +34 -87
  160. package/src/app/utils/parser/python/parseFile.ts +30 -100
  161. package/src/app/utils/parser/typescript/parseFile.ts +17 -52
  162. package/src/app/utils/selectParserLanguage.ts +39 -0
  163. package/src/cli/formatAuditRuleFailures.ts +21 -0
  164. package/src/cli/runAuditAsync.ts +41 -0
  165. package/src/components/Breadcrumb.tsx +5 -4
  166. package/src/components/ExportPanel.tsx +53 -0
  167. package/src/components/Header.tsx +1 -0
  168. package/src/components/Loader.tsx +8 -2
  169. package/src/components/ProjectLoadError.tsx +15 -0
  170. package/src/components/SettingsPanel.tsx +184 -0
  171. package/src/components/Switch.tsx +9 -17
  172. package/src/components/ThemeToggle.tsx +2 -1
  173. package/src/components/ToggleSwitch.tsx +36 -0
  174. package/src/components/sidebar/Sidebar.tsx +14 -0
  175. package/src/components/sidebar/SidebarBadge.tsx +25 -0
  176. package/src/components/sidebar/SidebarRow.tsx +14 -0
  177. package/src/components/sidebar/SidebarSection.tsx +16 -0
  178. package/src/components/sidebar/SidebarTabs.tsx +58 -0
  179. package/src/contexts/SettingsContext.tsx +19 -20
  180. package/src/features/audit/adapters/inbound/react/AuditRuleList.tsx +76 -0
  181. package/src/features/audit/adapters/inbound/react/AuditRulePanel.tsx +30 -0
  182. package/src/features/audit/adapters/inbound/react/CycleInspector.tsx +116 -0
  183. package/src/features/audit/adapters/inbound/react/CyclicDependenciesRuleDetails.tsx +124 -0
  184. package/src/features/audit/adapters/inbound/react/useCycleSelection.ts +47 -0
  185. package/src/features/audit/application/use-cases/createAuditFromSnapshot.ts +28 -0
  186. package/src/features/audit/application/use-cases/resolveSelectedCycleIds.ts +18 -0
  187. package/src/features/audit/composition/createAuditAsync.ts +11 -0
  188. package/src/features/audit/domain/evaluateAuditRules.ts +42 -0
  189. package/src/features/audit/domain/hasBlockingAuditRuleFailure.ts +6 -0
  190. package/src/features/audit/domain/resolveAuditConfiguration.ts +27 -0
  191. package/src/features/audit/utils/cycleVisualization.ts +86 -0
  192. package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeDependencyImportsAsync.ts +172 -0
  193. package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeTypeScriptImportsAsync.ts +6 -0
  194. package/src/features/graph-view/adapters/inbound/react/DependencyGraphView.tsx +184 -0
  195. package/src/features/graph-view/adapters/inbound/react/GraphZoomControls.tsx +48 -0
  196. package/src/features/graph-view/adapters/inbound/react/applyGraphInteractionPresentation.ts +35 -0
  197. package/src/features/graph-view/adapters/inbound/react/createGraphViewModel.ts +240 -0
  198. package/src/features/graph-view/adapters/inbound/react/createGraphViewStyles.ts +37 -0
  199. package/src/features/graph-view/adapters/inbound/react/useGraphFocus.ts +104 -0
  200. package/src/features/graph-view/adapters/inbound/react/useGraphInteractions.ts +50 -0
  201. package/src/features/graph-view/adapters/inbound/react/useGraphProjection.ts +71 -0
  202. package/src/features/graph-view/adapters/inbound/react/useGraphViewport.ts +48 -0
  203. package/src/features/graph-view/domain/getDependencyHighlightClasses.ts +39 -0
  204. package/src/features/graph-view/domain/reduceGraphInteraction.ts +23 -0
  205. package/src/features/graph-view/utils/createCompoundOpacityIndex.ts +38 -0
  206. package/src/features/graph-view/utils/projectVisibleGraph.ts +94 -0
  207. package/src/features/graph-view/utils/readNodeDefinitionId.ts +7 -0
  208. package/src/features/graph-view/utils/removeEmptyStructuralNodes.ts +27 -0
  209. package/src/features/project-analysis/adapters/outbound/filesystem/readProjectSnapshotAsync.ts +12 -0
  210. package/src/features/project-analysis/application/use-cases/createProjectSnapshotReader.ts +29 -0
  211. package/src/features/project-analysis/composition/loadProjectOverviewAsync.ts +14 -0
  212. package/src/features/project-analysis/composition/loadProjectSnapshotAsync.ts +12 -0
  213. package/src/features/project-tree/adapters/inbound/react/ProjectTreePanel.tsx +52 -0
  214. package/src/features/project-tree/adapters/inbound/react/useProjectTreeExpansion.ts +46 -0
  215. package/src/features/project-tree/application/use-cases/buildProjectTree.ts +61 -0
  216. package/src/features/project-tree/application/use-cases/resolveProjectTreeNavigation.ts +13 -0
  217. package/src/features/project-tree/utils/findProjectTreeNode.ts +14 -0
  218. package/src/features/project-tree/utils/findProjectTreeNodeByGraphPackage.ts +21 -0
  219. package/src/features/project-tree/utils/getProjectTreeAncestorIds.ts +26 -0
  220. package/src/features/settings/utils/readSettingsEnvironment.ts +53 -0
  221. package/src/i18n/en.ts +21 -2
  222. package/src/i18n/i18n.ts +2 -3
  223. package/src/layouts/breadthfirst/style.ts +1 -0
  224. package/src/layouts/circle/style.ts +1 -0
  225. package/src/layouts/concentric/style.ts +1 -0
  226. package/src/layouts/elk/layout.ts +1 -3
  227. package/src/layouts/elk/style.ts +1 -0
  228. package/src/layouts/getWeightBuckets.ts +3 -1
  229. package/src/layouts/grid/style.ts +1 -0
  230. package/src/layouts/index.ts +0 -4
  231. package/src/layouts/style.ts +172 -25
  232. package/src/screens/home/Home.tsx +73 -25
  233. package/src/screens/home/HomeGraph.tsx +43 -0
  234. package/src/screens/home/HomeSidebar.tsx +129 -0
  235. package/src/shared/types/index.ts +0 -9
  236. package/src/shared/utils/getProjectName.ts +4 -1
  237. package/src/shared/utils/parseProjectPath.ts +1 -0
  238. package/src/shared/utils/toPosix.ts +1 -1
  239. package/src/types/audit.ts +76 -0
  240. package/src/types/auditVisualization.ts +22 -0
  241. package/src/types/graphInteraction.ts +9 -0
  242. package/src/types/parserSelection.ts +11 -0
  243. package/src/types/projectAnalysis.ts +20 -0
  244. package/src/types/projectAnalysisActionResult.ts +2 -0
  245. package/src/types/projectTree.ts +7 -0
  246. package/src/utils/filter/filterByPackagePrefix.ts +25 -7
  247. package/src/utils/filter/filterEmptyPackages.ts +28 -29
  248. package/src/utils/filter/filterSubPackagesFromDepth.ts +20 -17
  249. package/src/utils/filter/filterVendorPackages.ts +1 -1
  250. package/src/utils/filter/isIntrinsicGraphNode.ts +8 -0
  251. package/src/utils/filter/toggleCompoundNodes.ts +41 -31
  252. package/src/utils/runProjectAnalysisActionAsync.ts +14 -0
  253. package/tsconfig.json +11 -3
  254. package/.next/app-build-manifest.json +0 -29
  255. package/.next/cache/.previewinfo +0 -1
  256. package/.next/cache/.rscinfo +0 -1
  257. package/.next/cache/.tsbuildinfo +0 -1
  258. package/.next/cache/chrome-devtools-workspace-uuid +0 -1
  259. package/.next/cache/eslint/.cache_6t30dc +0 -1
  260. package/.next/cache/webpack/client-production/0.pack +0 -4
  261. package/.next/cache/webpack/client-production/1.pack +0 -0
  262. package/.next/cache/webpack/client-production/10.pack +0 -0
  263. package/.next/cache/webpack/client-production/11.pack +0 -0
  264. package/.next/cache/webpack/client-production/12.pack +0 -0
  265. package/.next/cache/webpack/client-production/13.pack +0 -0
  266. package/.next/cache/webpack/client-production/14.pack +0 -0
  267. package/.next/cache/webpack/client-production/15.pack +0 -0
  268. package/.next/cache/webpack/client-production/16.pack +0 -0
  269. package/.next/cache/webpack/client-production/2.pack +0 -0
  270. package/.next/cache/webpack/client-production/3.pack +0 -0
  271. package/.next/cache/webpack/client-production/4.pack +0 -0
  272. package/.next/cache/webpack/client-production/5.pack +0 -0
  273. package/.next/cache/webpack/client-production/6.pack +0 -0
  274. package/.next/cache/webpack/client-production/7.pack +0 -0
  275. package/.next/cache/webpack/client-production/8.pack +0 -0
  276. package/.next/cache/webpack/client-production/9.pack +0 -0
  277. package/.next/cache/webpack/client-production/index.pack +0 -0
  278. package/.next/cache/webpack/client-production/index.pack.old +0 -0
  279. package/.next/cache/webpack/edge-server-production/0.pack +0 -0
  280. package/.next/cache/webpack/edge-server-production/index.pack +0 -0
  281. package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
  282. package/.next/cache/webpack/server-production/0.pack +0 -0
  283. package/.next/cache/webpack/server-production/1.pack +0 -0
  284. package/.next/cache/webpack/server-production/10.pack +0 -4
  285. package/.next/cache/webpack/server-production/11.pack +0 -0
  286. package/.next/cache/webpack/server-production/12.pack +0 -0
  287. package/.next/cache/webpack/server-production/13.pack +0 -0
  288. package/.next/cache/webpack/server-production/14.pack +0 -0
  289. package/.next/cache/webpack/server-production/15.pack +0 -0
  290. package/.next/cache/webpack/server-production/16.pack +0 -0
  291. package/.next/cache/webpack/server-production/17.pack +0 -0
  292. package/.next/cache/webpack/server-production/18.pack +0 -4
  293. package/.next/cache/webpack/server-production/2.pack +0 -0
  294. package/.next/cache/webpack/server-production/3.pack +0 -0
  295. package/.next/cache/webpack/server-production/4.pack +0 -0
  296. package/.next/cache/webpack/server-production/5.pack +0 -0
  297. package/.next/cache/webpack/server-production/6.pack +0 -0
  298. package/.next/cache/webpack/server-production/7.pack +0 -0
  299. package/.next/cache/webpack/server-production/8.pack +0 -0
  300. package/.next/cache/webpack/server-production/9.pack +0 -0
  301. package/.next/cache/webpack/server-production/index.pack +0 -0
  302. package/.next/cache/webpack/server-production/index.pack.old +0 -0
  303. package/.next/diagnostics/build-diagnostics.json +0 -6
  304. package/.next/diagnostics/framework.json +0 -1
  305. package/.next/server/app/index.html +0 -1
  306. package/.next/server/app/index.meta +0 -7
  307. package/.next/server/app/index.rsc +0 -20
  308. package/.next/server/chunks/548.js +0 -6
  309. package/.next/server/chunks/610.js +0 -7
  310. package/.next/server/chunks/985.js +0 -22
  311. package/.next/server/middleware-react-loadable-manifest.js +0 -1
  312. package/.next/server/pages/_app.js +0 -1
  313. package/.next/server/pages/_app.js.nft.json +0 -1
  314. package/.next/server/pages/_document.js +0 -1
  315. package/.next/server/pages/_document.js.nft.json +0 -1
  316. package/.next/server/pages/_error.js +0 -19
  317. package/.next/server/pages/_error.js.nft.json +0 -1
  318. package/.next/server/webpack-runtime.js +0 -1
  319. package/.next/static/5HapMtlwNHlJNa0mJQNsK/_buildManifest.js +0 -1
  320. package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -1
  321. package/.next/static/chunks/680-55ad17895c8fb70b.js +0 -1
  322. package/.next/static/chunks/90542734-29e255269788f1bd.js +0 -1
  323. package/.next/static/chunks/91dbc596-b9cdccd3f5cba95d.js +0 -1
  324. package/.next/static/chunks/964-b440f7af22c41ca5.js +0 -1
  325. package/.next/static/chunks/app/_not-found/page-11e4fea8e290f304.js +0 -1
  326. package/.next/static/chunks/app/layout-8aae7fba5ed8afb3.js +0 -1
  327. package/.next/static/chunks/app/page-91450b1230da8bca.js +0 -1
  328. package/.next/static/chunks/framework-bc35dade6ff9684e.js +0 -1
  329. package/.next/static/chunks/main-9e86d333c1e02dd1.js +0 -1
  330. package/.next/static/chunks/main-app-69a9ff75ff3465ca.js +0 -1
  331. package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -1
  332. package/.next/static/chunks/pages/_error-03529f2c21436739.js +0 -1
  333. package/.next/static/chunks/webpack-7adfafc806738767.js +0 -1
  334. package/.next/static/css/ec31779168107a11.css +0 -3
  335. package/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
  336. package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
  337. package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
  338. package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
  339. package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
  340. package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
  341. package/.next/trace +0 -2
  342. package/.next/types/app/layout.ts +0 -84
  343. package/.next/types/app/page.ts +0 -84
  344. package/.next/types/cache-life.d.ts +0 -141
  345. package/.next/types/package.json +0 -1
  346. package/src/app/actions/graph.actions.ts +0 -25
  347. package/src/app/utils/parser/cpp/extractCppPackageFromImport.ts +0 -18
  348. package/src/app/utils/parser/delphi/extractPackageFromImport.ts +0 -21
  349. package/src/app/utils/parser/java/extractJavaPackageFromImport.ts +0 -39
  350. package/src/app/utils/parser/java/getIntrinsicPackagesRecursive.ts +0 -33
  351. package/src/app/utils/parser/kotlin/extractPackageFromImport.ts +0 -19
  352. package/src/app/utils/parser/python/extractPythonPackageFromImport.ts +0 -18
  353. package/src/app/utils/parser/typescript/extractTypeScriptPackageFromImport.ts +0 -18
  354. package/src/components/Cytoscape.tsx +0 -23
  355. package/src/components/Setting.tsx +0 -17
  356. package/src/components/Settings.tsx +0 -189
  357. package/src/components/ZoomInput.tsx +0 -94
  358. package/src/components/useCytoscape.ts +0 -343
  359. package/src/layouts/getLayoutStyle.ts +0 -19
  360. package/src/shared/utils/detectLanguage.ts +0 -255
  361. package/src/shared/utils/getJsonAsync.ts +0 -13
  362. package/src/shared/utils/parseEnv.ts +0 -91
  363. package/src/store/useLocalStorage.ts +0 -29
  364. package/src/utils/hasChildren.ts +0 -7
  365. /package/.next/{react-loadable-manifest.json → server/app/_global-error/page/react-loadable-manifest.json} +0 -0
  366. /package/.next/static/chunks/{polyfills-42372ed130431b0a.js → 0cz1d0mv5g_q7.js} +0 -0
  367. /package/.next/static/{5HapMtlwNHlJNa0mJQNsK → rjdzHqzPw2GCNhDbjcu0-}/_ssgManifest.js +0 -0
@@ -1,189 +0,0 @@
1
- 'use client';
2
- import dynamic from 'next/dynamic';
3
- import { ChevronDownIcon, DownloadIcon } from 'lucide-react';
4
- import { Select, Slider } from 'radix-ui';
5
- import type React from 'react';
6
- import Setting from '@/components/Setting';
7
- import Switch from '@/components/Switch';
8
- import { useSettings } from '@/contexts/SettingsContext';
9
- import { t } from '@/i18n/i18n';
10
- import { downloadAuditJsonAction, downloadAuditXmlAction } from '@/app/actions/audit.actions';
11
-
12
- const Settings: React.FC = () => {
13
- const {
14
- cytoscapeLayout,
15
- cytoscapeLayoutSpacing,
16
- maxSubPackageDepth,
17
- showCompoundNodes,
18
- showVendorPackages,
19
- subPackageDepth,
20
- setCytoscapeLayout,
21
- setCytoscapeLayoutSpacing,
22
- setSubPackageDepth,
23
- toggleShowCompoundNodes,
24
- toggleShowVendorPackages,
25
- } = useSettings();
26
-
27
- const handleDownloadJson = async () => {
28
- const { data, filename } = await downloadAuditJsonAction();
29
- const blob = new Blob([data], { type: 'application/json' });
30
- const url = URL.createObjectURL(blob);
31
- const a = document.createElement('a');
32
- a.href = url;
33
- a.download = filename;
34
- a.click();
35
- URL.revokeObjectURL(url);
36
- };
37
-
38
- const handleDownloadXml = async () => {
39
- const { data, filename } = await downloadAuditXmlAction();
40
- const blob = new Blob([data], { type: 'application/xml' });
41
- const url = URL.createObjectURL(blob);
42
- const a = document.createElement('a');
43
- a.href = url;
44
- a.download = filename;
45
- a.click();
46
- URL.revokeObjectURL(url);
47
- };
48
-
49
- return (
50
- <div className="md:pt-14 border-r bg-neutral-100 border-r-neutral-200 dark:border-r-neutral-800 dark:bg-neutral-950">
51
- {/* Audit Download */}
52
- <h3>{t('settings.download')}</h3>
53
- <div>
54
- {/* JSON Audit Download */}
55
- <Setting>
56
- <button
57
- onClick={handleDownloadJson}
58
- className="flex flex-row items-center content-start text-xs cursor-pointer hover:text-blue-600 dark:hover:text-blue-400"
59
- >
60
- <DownloadIcon size={8} className="mr-1" />
61
- <span>JSON</span>
62
- </button>
63
- </Setting>
64
- {/* XML Audit Download */}
65
- <Setting>
66
- <button
67
- onClick={handleDownloadXml}
68
- className="flex flex-row items-center content-start text-xs cursor-pointer hover:text-blue-600 dark:hover:text-blue-400"
69
- >
70
- <DownloadIcon size={8} className="mr-1" />
71
- <span>XML</span>
72
- </button>
73
- </Setting>
74
- </div>
75
-
76
- <h3>{t('settings.filter')}</h3>
77
- {/* Whether to show vendor packages */}
78
- <Setting>
79
- <Switch
80
- id="switch-show-vendor-packages"
81
- label={t('settings.showVendorPackages')}
82
- onToggle={() => {
83
- toggleShowVendorPackages();
84
- }}
85
- value={showVendorPackages}
86
- />
87
- </Setting>
88
-
89
- {/* Whether to show compound nodes */}
90
- <Setting>
91
- <Switch
92
- id="switch-show-compound-nodes"
93
- label={t('settings.showCompoundNodes')}
94
- onToggle={() => {
95
- toggleShowCompoundNodes();
96
- }}
97
- value={showCompoundNodes}
98
- />
99
- </Setting>
100
-
101
- {/* How many sub package levels to show */}
102
- <>
103
- <h3>{`${t('settings.subPackageDepth')}: ${subPackageDepth}`}</h3>
104
- <Setting>
105
- <Slider.Root
106
- id="subPackageDepth"
107
- min={1}
108
- max={maxSubPackageDepth}
109
- step={1}
110
- value={[subPackageDepth]}
111
- onValueChange={([v]) => setSubPackageDepth(Number(v.toFixed(1)))}
112
- aria-label="Subpackage depth"
113
- className="relative flex h-5 w-56 touch-none select-none items-center"
114
- >
115
- <Slider.Track className="relative h-1.5 grow rounded-full bg-neutral-200 dark:bg-neutral-800">
116
- <Slider.Range className="absolute h-1.5 rounded-full bg-blue-600 dark:bg-blue-400" />
117
- </Slider.Track>
118
- <Slider.Thumb className="block h-4 w-4 rounded-full border border-neutral-300 bg-white shadow focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-neutral-600 dark:bg-neutral-100" />
119
- </Slider.Root>
120
- </Setting>
121
- </>
122
-
123
- <h3>{t('settings.layout')}</h3>
124
- <Setting>
125
- <Select.Root value={cytoscapeLayout} onValueChange={setCytoscapeLayout}>
126
- <Select.Trigger
127
- aria-label={t('cytoscapeLayout')}
128
- className="inline-flex items-center justify-between w-44 h-9 rounded-md px-3 border"
129
- >
130
- <Select.Value className="text-foreground" />
131
- <Select.Icon>
132
- <ChevronDownIcon />
133
- </Select.Icon>
134
- </Select.Trigger>
135
- <Select.Portal>
136
- <Select.Content
137
- position="popper"
138
- side="bottom"
139
- align="start"
140
- sideOffset={6}
141
- className="z-50 min-w-(--radix-select-trigger-width) rounded-md border bg-white dark:bg-neutral-900 shadow-md"
142
- >
143
- <Select.Viewport className="p-1">
144
- <Select.Group>
145
- {['breadthfirst', 'circle', 'concentric', 'elk', 'grid'].map(layout => (
146
- <Select.Item
147
- key={layout}
148
- value={layout}
149
- textValue={t(layout)}
150
- className="px-2 py-1.5 rounded hover:bg-neutral-100 dark:hover:bg-neutral-800"
151
- >
152
- <Select.ItemText>{t(layout)}</Select.ItemText>
153
- </Select.Item>
154
- ))}
155
- </Select.Group>
156
- </Select.Viewport>
157
- </Select.Content>
158
- </Select.Portal>
159
- </Select.Root>
160
- </Setting>
161
-
162
- <h3>
163
- {t('settings.layoutSpacing')}: {cytoscapeLayoutSpacing}
164
- </h3>
165
- {/* Which Cytoscape layout spacing */}
166
- <Setting>
167
- <Slider.Root
168
- id="spacing"
169
- min={0.1}
170
- max={1}
171
- step={0.1}
172
- value={[cytoscapeLayoutSpacing]}
173
- onValueChange={([v]) => setCytoscapeLayoutSpacing(Number(v.toFixed(1)))}
174
- aria-label="Layout spacing"
175
- className="relative flex h-5 w-56 touch-none select-none items-center"
176
- >
177
- <Slider.Track className="relative h-1.5 grow rounded-full bg-neutral-200 dark:bg-neutral-800">
178
- <Slider.Range className="absolute h-1.5 rounded-full bg-blue-600 dark:bg-blue-400" />
179
- </Slider.Track>
180
- <Slider.Thumb className="block h-4 w-4 rounded-full border border-neutral-300 bg-white shadow focus:outline-none focus:ring-2 focus:ring-blue-500 dark:border-neutral-600 dark:bg-neutral-100" />
181
- </Slider.Root>
182
- </Setting>
183
- </div>
184
- );
185
- };
186
-
187
- export default dynamic(() => Promise.resolve(Settings), {
188
- ssr: false,
189
- });
@@ -1,94 +0,0 @@
1
- 'use client';
2
- import React, { useEffect, useState } from 'react';
3
- import { Core } from 'cytoscape';
4
- import { CircleDotDashedIcon } from 'lucide-react';
5
-
6
- interface IZoomInput {
7
- readonly cyInstance: Core | null;
8
- }
9
-
10
- export default function ZoomInput({ cyInstance }: IZoomInput) {
11
- const [zoom, setZoom] = useState<number>(1);
12
- const [minZoom, setMinZoom] = useState<number>(0.1);
13
- const [maxZoom, setMaxZoom] = useState<number>(2);
14
-
15
- // Sync initial zoom + bounds + subscribe to zoom events
16
- useEffect(() => {
17
- if (!cyInstance) return;
18
-
19
- // Initialize from cy
20
- setZoom(cyInstance.zoom());
21
- setMinZoom(cyInstance.minZoom());
22
- setMaxZoom(cyInstance.maxZoom());
23
-
24
- const handleZoom = () => {
25
- setZoom(cyInstance.zoom());
26
- };
27
-
28
- cyInstance.on('zoom', handleZoom);
29
-
30
- return () => {
31
- cyInstance.off('zoom', handleZoom);
32
- };
33
- }, [cyInstance]);
34
-
35
- // Slider change -> set zoom, anchored at viewport centre
36
- const handleSliderChange = (e: React.ChangeEvent<HTMLInputElement>) => {
37
- if (!cyInstance) return;
38
- const level = parseFloat(e.target.value);
39
-
40
- // Clamp to current min/max just in case
41
- const clamped = Math.min(maxZoom, Math.max(minZoom, level));
42
-
43
- // Anchor zoom around the canvas centre (in rendered coords)
44
- const renderedPosition = {
45
- x: cyInstance.width() / 2,
46
- y: cyInstance.height() / 2,
47
- };
48
-
49
- cyInstance.zoom({ level: clamped, renderedPosition });
50
- setZoom(clamped);
51
- };
52
-
53
- // Zoom to fit button
54
- const handleZoomToFit = () => {
55
- if (!cyInstance) return;
56
-
57
- // Fit all elements with a bit of padding
58
- cyInstance.fit(undefined, 50);
59
-
60
- const nextZoom = cyInstance.zoom();
61
- setZoom(nextZoom);
62
- // If you want, you could also refresh min/max here:
63
- // setMinZoom(cyInstance.minZoom());
64
- // setMaxZoom(cyInstance.maxZoom());
65
- };
66
-
67
- return (
68
- <div className="p-4 flex items-center justify-center gap-2 border-t border-t-gray-200 dark:border-t-gray-800">
69
- <label htmlFor="zoom">Zoom:</label>
70
-
71
- <button
72
- type="button"
73
- title="Zoom to fit"
74
- onClick={handleZoomToFit}
75
- className="p-1 rounded hover:bg-gray-100 dark:hover:bg-gray-800"
76
- >
77
- <CircleDotDashedIcon className="cursor-pointer" />
78
- </button>
79
-
80
- <input
81
- id="zoom"
82
- type="range"
83
- min={minZoom}
84
- max={maxZoom}
85
- step="0.05"
86
- value={zoom}
87
- onChange={handleSliderChange}
88
- className="w-64"
89
- />
90
-
91
- <span className="text-sm">{(zoom * 100).toFixed(0)}%</span>
92
- </div>
93
- );
94
- }
@@ -1,343 +0,0 @@
1
- 'use client';
2
- import { useTheme } from 'next-themes';
3
- import { useCallback, useEffect, useRef, useState } from 'react';
4
-
5
- import cytoscape, {
6
- Core,
7
- LayoutOptions,
8
- type ElementsDefinition,
9
- type NodeDefinition,
10
- type Layouts,
11
- } from 'cytoscape';
12
-
13
- import { useSettings } from '@/contexts/SettingsContext';
14
- import { getStyle as getCommonStyle, getCanvasBg } from '@/layouts/style';
15
- import {
16
- getBreadthfirstStyle,
17
- getCircleStyle,
18
- getConcentricStyle,
19
- getElkStyle,
20
- getGridStyle,
21
- } from '@/layouts';
22
- import { LAYOUTS } from '@/layouts/constants';
23
-
24
- import { filterByPackagePrefix } from '@/utils/filter/filterByPackagePrefix';
25
- import { filterVendorPackages } from '@/utils/filter/filterVendorPackages';
26
- import { filterEmptyPackages } from '@/utils/filter/filterEmptyPackages';
27
- import { filterSubPackagesByDepth, getMaxDepth } from '@/utils/filter/filterSubPackagesFromDepth';
28
- import { toggleCompoundNodes } from '@/utils/filter/toggleCompoundNodes';
29
- import { hasChildren } from '@/utils/hasChildren';
30
-
31
- export function useCytoscape(
32
- elements: ElementsDefinition | null,
33
- currentPackage: string,
34
- setCurrentPackage: (path: string) => void
35
- ) {
36
- const cyRef = useRef<HTMLDivElement>(null);
37
- const [filteredElements, setFilteredElements] = useState<ElementsDefinition | null>(null);
38
- const [cyInstance, setCyInstance] = useState<Core | null>(null);
39
-
40
- // Keep the running layout so we can stop it on swap
41
- const layoutRef = useRef<Layouts | null>(null);
42
-
43
- // Refs for latest data so event handlers don't need to be re-created
44
- const elementsRef = useRef<ElementsDefinition | null>(null);
45
- const filteredElementsRef = useRef<ElementsDefinition | null>(null);
46
- elementsRef.current = elements;
47
- filteredElementsRef.current = filteredElements;
48
-
49
- const {
50
- cytoscapeLayout,
51
- cytoscapeLayoutSpacing,
52
- showCompoundNodes,
53
- showVendorPackages,
54
- subPackageDepth,
55
- setMaxSubPackageDepth,
56
- } = useSettings();
57
-
58
- const { resolvedTheme } = useTheme();
59
- const theme = (resolvedTheme === 'dark' ? 'dark' : 'light') as 'dark' | 'light';
60
-
61
- /** 1) Compute filteredElements when inputs change */
62
- useEffect(() => {
63
- if (!elements) return;
64
-
65
- const afterCompoundNodeFilter = toggleCompoundNodes(
66
- elements,
67
- showCompoundNodes,
68
- currentPackage
69
- );
70
-
71
- const afterPkgFilter = filterByPackagePrefix(
72
- afterCompoundNodeFilter,
73
- currentPackage.replace(/\//g, '.')
74
- );
75
-
76
- const afterSubPkgFilter = filterSubPackagesByDepth(afterPkgFilter, true, subPackageDepth);
77
-
78
- const afterVendorPkgFilter = showVendorPackages
79
- ? afterSubPkgFilter
80
- : filterVendorPackages(afterSubPkgFilter);
81
-
82
- const nonEmptyCurrentPackage = filterEmptyPackages(currentPackage, afterVendorPkgFilter);
83
- if (nonEmptyCurrentPackage !== currentPackage) {
84
- setCurrentPackage(nonEmptyCurrentPackage);
85
- return;
86
- }
87
-
88
- const finalElements: ElementsDefinition = {
89
- nodes: afterVendorPkgFilter.nodes.map(node => {
90
- const label = !currentPackage.length
91
- ? node.data.id
92
- : node.data.id?.slice(currentPackage.length + 1);
93
- return {
94
- group: 'nodes',
95
- classes: node.classes || '',
96
- data: { ...node.data, label },
97
- } as NodeDefinition;
98
- }),
99
- edges: afterVendorPkgFilter.edges,
100
- };
101
-
102
- setFilteredElements(finalElements);
103
- setMaxSubPackageDepth(getMaxDepth(elements));
104
- }, [
105
- elements,
106
- currentPackage,
107
- setCurrentPackage,
108
- showCompoundNodes,
109
- showVendorPackages,
110
- subPackageDepth,
111
- setMaxSubPackageDepth,
112
- ]);
113
-
114
- /** 2) Helper for layout options */
115
- const makeLayoutOpts = useCallback(
116
- (name: LayoutOptions['name']): LayoutOptions & { [k: string]: unknown } => ({
117
- ...LAYOUTS[name],
118
- spacingFactor: cytoscapeLayoutSpacing,
119
- nodeDimensionsIncludeLabels: true,
120
- fit: true,
121
- animate: false,
122
- animationDuration: 400,
123
- }),
124
- [cytoscapeLayoutSpacing]
125
- );
126
-
127
- /** 3) Run (or re-run) layout safely; stop any previous instance */
128
- const runLayoutSafe = useCallback(
129
- (cy: Core, name: LayoutOptions['name']) => {
130
- try {
131
- layoutRef.current?.stop();
132
- } catch {
133
- // Ignore
134
- }
135
- layoutRef.current = null;
136
-
137
- if (!cy || cy.destroyed()) return;
138
-
139
- cy.resize();
140
-
141
- requestAnimationFrame(() => {
142
- if (!cy || cy.destroyed()) return;
143
-
144
- const layout = cy.layout(makeLayoutOpts(name));
145
- layoutRef.current = layout;
146
-
147
- const onStop = () => {
148
- if (cy.destroyed()) return;
149
- cy.fit(undefined, 50);
150
- };
151
- cy.one('layoutstop', onStop);
152
-
153
- layout.run();
154
- });
155
- },
156
- [makeLayoutOpts]
157
- );
158
-
159
- /** 4) Init Cytoscape ONCE (step 1 already applied: [] deps) */
160
- useEffect(() => {
161
- if (!cyRef.current) return;
162
-
163
- const cy = cytoscape({
164
- container: cyRef.current,
165
- elements: [],
166
- hideEdgesOnViewport: true,
167
- minZoom: 0.01,
168
- maxZoom: 2,
169
- selectionType: 'additive',
170
- style: getCommonStyle({ nodes: [], edges: [] } as ElementsDefinition, 'light'),
171
- userPanningEnabled: true,
172
- });
173
-
174
- setCyInstance(cy);
175
- cyRef.current.style.background = getCanvasBg('light');
176
-
177
- const handleResize = () => {
178
- if (cy.destroyed()) return;
179
- cy.fit(undefined, 50);
180
- };
181
- const observer = new ResizeObserver(() => requestAnimationFrame(handleResize));
182
- observer.observe(cyRef.current);
183
-
184
- return () => {
185
- try {
186
- layoutRef.current?.stop();
187
- } catch {
188
- // Ignore
189
- }
190
- layoutRef.current = null;
191
-
192
- observer.disconnect();
193
- cy.destroy();
194
- setCyInstance(null);
195
- };
196
- }, []);
197
-
198
- /**
199
- * 5) Data Update
200
- * - This effect updates the elements and node classes/handlers
201
- * - It DOES NOT run layout anymore
202
- * - Layout runs only in effect (6) => avoids double layout runs
203
- */
204
- useEffect(() => {
205
- if (!cyInstance || !filteredElements || cyInstance.destroyed()) return;
206
-
207
- cyInstance.batch(() => {
208
- cyInstance.elements().remove();
209
- cyInstance.add(filteredElements);
210
- });
211
-
212
- // Mark parents + dblclick handler based on latest elementsRef
213
- cyInstance.nodes().forEach(node => {
214
- const rawNode = filteredElementsRef.current?.nodes.find(
215
- elm => elm.data.id === node.data().id
216
- ) as NodeDefinition | undefined;
217
-
218
- const allNodes = elementsRef.current?.nodes ?? [];
219
- node.removeClass('isParent');
220
- node.off('dblclick');
221
-
222
- if (!rawNode) return;
223
- if (!hasChildren(rawNode, allNodes)) return;
224
-
225
- node.addClass('isParent');
226
- node.on('dblclick', () => setCurrentPackage(node.id().replace(/\./g, '/')));
227
- });
228
- }, [cyInstance, filteredElements, setCurrentPackage]);
229
-
230
- /**
231
- * 6) Single Layout Trigger
232
- *
233
- * Runs when:
234
- * - filteredElements changes (new data)
235
- * - layout name changes
236
- * - spacing changes
237
- *
238
- * - This is now the ONLY place that calls runLayoutSafe
239
- */
240
- useEffect(() => {
241
- if (!cyInstance || !filteredElements || cyInstance.destroyed()) return;
242
- runLayoutSafe(cyInstance, cytoscapeLayout as LayoutOptions['name']);
243
- }, [cyInstance, filteredElements, cytoscapeLayout, cytoscapeLayoutSpacing, runLayoutSafe]);
244
-
245
- /** 7) Attach interactive event handlers once (using refs for latest data) */
246
- useEffect(() => {
247
- if (!cyInstance) return;
248
- const cy = cyInstance;
249
-
250
- const updateHighlights = () => {
251
- if (cy.destroyed()) return;
252
- const selectedNodes = cy.nodes(':selected');
253
- const all = cy.elements();
254
- all.removeClass('hushed highlight highlight-outgoer highlight-incomer');
255
- if (selectedNodes.empty()) return;
256
- const keep = selectedNodes.union(selectedNodes.neighborhood());
257
- all.difference(keep).addClass('hushed');
258
- selectedNodes.addClass('highlight');
259
- selectedNodes.outgoers().addClass('highlight-outgoer');
260
- selectedNodes.incomers().addClass('highlight-incomer');
261
- };
262
-
263
- cy.on('select unselect', 'node', updateHighlights);
264
-
265
- cy.on('mouseover', 'node', event => {
266
- if (cy.destroyed()) return;
267
- const node = event.target;
268
-
269
- const fe = filteredElementsRef.current;
270
- const el = elementsRef.current;
271
- const rawNode = fe?.nodes.find(n => n.data.id === node.data().id) as
272
- | NodeDefinition
273
- | undefined;
274
-
275
- if (rawNode && el && hasChildren(rawNode, el.nodes)) {
276
- document.body.style.cursor = 'pointer';
277
- if (fe && hasChildren(rawNode, fe.nodes)) return;
278
- }
279
-
280
- cy.elements()
281
- .subtract(node.outgoers())
282
- .subtract(node.incomers())
283
- .subtract(node)
284
- .addClass('hushed');
285
- node.addClass('highlight');
286
- node.outgoers().addClass('highlight-outgoer');
287
- node.incomers().addClass('highlight-incomer');
288
- });
289
-
290
- cy.on('mouseout', 'node', () => {
291
- if (cy.destroyed()) return;
292
- document.body.style.cursor = 'default';
293
- updateHighlights();
294
- });
295
-
296
- let highlightDelay: ReturnType<typeof setTimeout>;
297
- cy.on('mouseover', 'edge', e => {
298
- if (cy.destroyed()) return;
299
- const edge = e.target;
300
- edge.addClass('highlight-dependency');
301
- highlightDelay = setTimeout(() => {
302
- if (cy.destroyed()) return;
303
- edge.source().addClass('highlight-dependency');
304
- edge.target().addClass('highlight-dependency');
305
- }, 150);
306
- });
307
-
308
- cy.on('mouseout', 'edge', e => {
309
- if (cy.destroyed()) return;
310
- const edge = e.target;
311
- edge.removeClass('highlight-dependency');
312
- clearTimeout(highlightDelay);
313
- edge.source().removeClass('highlight-dependency');
314
- edge.target().removeClass('highlight-dependency');
315
- });
316
-
317
- return () => {
318
- cy.removeAllListeners?.();
319
- document.body.style.cursor = 'default';
320
- };
321
- }, [cyInstance]);
322
-
323
- /** 8) Theme + layout-style live update */
324
- useEffect(() => {
325
- if (!cyInstance || !filteredElements || !cyRef.current) return;
326
-
327
- const getLayoutStyle =
328
- cytoscapeLayout === 'breadthfirst'
329
- ? getBreadthfirstStyle
330
- : cytoscapeLayout === 'circle'
331
- ? getCircleStyle
332
- : cytoscapeLayout === 'elk'
333
- ? getElkStyle
334
- : cytoscapeLayout === 'grid'
335
- ? getGridStyle
336
- : getConcentricStyle;
337
-
338
- cyInstance.style([...getCommonStyle(filteredElements, theme), ...getLayoutStyle()]).update();
339
- cyRef.current.style.background = getCanvasBg(theme);
340
- }, [cyInstance, filteredElements, theme, cytoscapeLayout]);
341
-
342
- return { cyRef, cyInstance };
343
- }
@@ -1,19 +0,0 @@
1
- import type { LayoutOptions } from 'cytoscape';
2
-
3
- import { getStyle as getBreadthfirstStyle } from '@/layouts/breadthfirst/style';
4
- import { getStyle as getCircleStyle } from '@/layouts/circle/style';
5
- import { getStyle as getConcentricStyle } from '@/layouts/concentric/style';
6
- import { getStyle as getGridStyle } from '@/layouts/grid/style';
7
-
8
- export function getLayoutStyle(cytoscapeLayout: LayoutOptions['name']) {
9
- switch (cytoscapeLayout) {
10
- case 'breadthfirst':
11
- return getBreadthfirstStyle();
12
- case 'circle':
13
- return getCircleStyle();
14
- case 'concentric':
15
- return getConcentricStyle();
16
- case 'grid':
17
- return getGridStyle();
18
- }
19
- }