pkgviz 0.7.7 → 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.
- package/.next/BUILD_ID +1 -1
- package/.next/app-path-routes-manifest.json +2 -1
- package/.next/build-manifest.json +15 -24
- package/.next/fallback-build-manifest.json +15 -0
- package/.next/images-manifest.json +14 -3
- package/.next/next-minimal-server.js.nft.json +1 -1
- package/.next/next-server.js.nft.json +1 -1
- package/.next/prerender-manifest.json +52 -16
- package/.next/required-server-files.js +349 -0
- package/.next/required-server-files.json +106 -75
- package/.next/routes-manifest.json +16 -6
- package/.next/server/app/_global-error/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_global-error/page/build-manifest.json +20 -0
- package/.next/server/app/_global-error/page/next-font-manifest.json +6 -0
- package/.next/server/app/_global-error/page/server-reference-manifest.json +4 -0
- package/.next/server/app/_global-error/page.js +9 -0
- package/.next/server/app/_global-error/page.js.map +5 -0
- package/.next/server/app/_global-error/page.js.nft.json +1 -0
- package/.next/server/app/_global-error/page_client-reference-manifest.js +3 -0
- package/.next/server/app/_global-error.html +1 -0
- package/.next/server/app/_global-error.meta +22 -0
- package/.next/server/app/_global-error.rsc +15 -0
- package/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +20 -0
- package/.next/server/app/_global-error.segments/_full.segment.rsc +15 -0
- package/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -0
- package/.next/server/app/_not-found/page/app-paths-manifest.json +3 -0
- package/.next/server/app/_not-found/page/build-manifest.json +20 -0
- package/.next/server/app/_not-found/page/next-font-manifest.json +11 -0
- package/.next/server/app/_not-found/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/_not-found/page/server-reference-manifest.json +4 -0
- package/.next/server/app/_not-found/page.js +13 -2
- package/.next/server/app/_not-found/page.js.map +5 -0
- package/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/.next/server/app/_not-found/page_client-reference-manifest.js +3 -1
- package/.next/server/app/_not-found.html +1 -1
- package/.next/server/app/_not-found.meta +19 -0
- package/.next/server/app/_not-found.rsc +18 -19
- package/.next/server/app/_not-found.segments/_full.segment.rsc +18 -0
- package/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +24 -0
- package/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -0
- package/.next/server/app/favicon.ico/route/app-paths-manifest.json +3 -0
- package/.next/server/app/favicon.ico/route/build-manifest.json +12 -0
- package/.next/server/app/favicon.ico/route.js +6 -1
- package/.next/server/app/favicon.ico/route.js.map +5 -0
- package/.next/server/app/favicon.ico/route.js.nft.json +1 -1
- package/.next/server/app/page/app-paths-manifest.json +3 -0
- package/.next/server/app/page/build-manifest.json +20 -0
- package/.next/server/app/page/next-font-manifest.json +11 -0
- package/.next/server/app/page/react-loadable-manifest.json +1 -0
- package/.next/server/app/page/server-reference-manifest.json +93 -0
- package/.next/server/app/page.js +16 -13
- package/.next/server/app/page.js.map +5 -0
- package/.next/server/app/page.js.nft.json +1 -1
- package/.next/server/app/page_client-reference-manifest.js +3 -1
- package/.next/server/app-paths-manifest.json +2 -1
- package/.next/server/chunks/[externals]__0l8ei7u._.js +3 -0
- package/.next/server/chunks/[externals]__0l8ei7u._.js.map +1 -0
- package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js +160 -0
- package/.next/server/chunks/[root-of-the-server]__1to-yfd._.js.map +1 -0
- package/.next/server/chunks/[turbopack]_runtime.js +807 -0
- package/.next/server/chunks/[turbopack]_runtime.js.map +10 -0
- package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js +3 -0
- package/.next/server/chunks/_next-internal_server_app_favicon_ico_route_actions_0g2jjls.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js +28 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0agsrep._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0f_e7c8._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__0yqn68e._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js +14 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__112mz-6._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__11_76b7._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__12ovu0c._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__16pmw__._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js +33 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1f2jx51._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__1rn09vt._.js.map +1 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js +3 -0
- package/.next/server/chunks/ssr/[root-of-the-server]__20e4gkp._.js.map +1 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js +807 -0
- package/.next/server/chunks/ssr/[turbopack]_runtime.js.map +10 -0
- package/.next/server/chunks/ssr/_1acy_2s._.js +158 -0
- package/.next/server/chunks/ssr/_1acy_2s._.js.map +1 -0
- package/.next/server/chunks/ssr/_1rh2tf9._.js +367 -0
- package/.next/server/chunks/ssr/_1rh2tf9._.js.map +1 -0
- package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app__global-error_page_actions_0zi5s8-.js.map +1 -0
- package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js +3 -0
- package/.next/server/chunks/ssr/_next-internal_server_app__not-found_page_actions_0pt47yr.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_01xbj_9._.js +33 -0
- package/.next/server/chunks/ssr/node_modules_01xbj_9._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_1c5ky4f._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js +6 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_1n3w9lb._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_0wpq8j3._.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_forbidden_0symwr9.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_global-error_0q-w892.js.map +1 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js +3 -0
- package/.next/server/chunks/ssr/node_modules_next_dist_client_components_builtin_unauthorized_0l_sp0x.js.map +1 -0
- package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js +3 -0
- package/.next/server/chunks/ssr/src_app_loading_tsx_01g_-m0._.js.map +1 -0
- package/.next/server/middleware-build-manifest.js +24 -1
- package/.next/server/middleware-manifest.json +2 -2
- package/.next/server/next-font-manifest.js +1 -1
- package/.next/server/next-font-manifest.json +15 -1
- package/.next/server/pages/404.html +1 -1
- package/.next/server/pages/500.html +1 -1
- package/.next/server/pages-manifest.json +2 -4
- package/.next/server/prefetch-hints.json +25 -0
- package/.next/server/server-reference-manifest.js +1 -1
- package/.next/server/server-reference-manifest.json +94 -1
- package/.next/static/chunks/19mx3mg6lkumu.js +1 -0
- package/.next/static/chunks/1las_6j17xa9p.js +1 -0
- package/.next/static/chunks/1xk6snnh6e5_j.css +3 -0
- package/.next/static/chunks/2-rtuqsgzmno4.js +22 -0
- package/.next/static/chunks/27t_qfc-3_lzs.js +1 -0
- package/.next/static/chunks/2sswp23h6zh08.js +345 -0
- package/.next/static/chunks/310vm2bl3xxpt.js +31 -0
- package/.next/static/chunks/3fntmmi971322.js +1 -0
- package/.next/static/chunks/turbopack-1b6uko1cu_h42.js +1 -0
- package/.next/static/media/4fa387ec64143e14-s.2tuy5pz7dlieh.woff2 +0 -0
- package/.next/static/media/53b9e256198e5412-s.390ncx5urfkfu.woff2 +0 -0
- package/.next/static/media/5ce348bf30bf5439-s.31988l_ccedte.woff2 +0 -0
- package/.next/static/media/6306c77e7c8268e4-s.2dbetqa9o8jxf.woff2 +0 -0
- package/.next/static/media/7178b3e590c64307-s.21jp631_3pja2.woff2 +0 -0
- package/.next/static/media/797e433ab948586e-s.p.0r6juujl39pe6.woff2 +0 -0
- package/.next/static/media/7d817b4c03b0c5f1-s.1uyisp29ctx0d.woff2 +0 -0
- package/.next/static/media/8a480f0b521d4e75-s.1qq4vpdcun5oj.woff2 +0 -0
- package/.next/static/media/bbc41e54d2fcbd21-s.1rgnod-3esatf.woff2 +0 -0
- package/.next/static/media/caa3a2e1cccd8315-s.p.0wgildi0cnwt9.woff2 +0 -0
- package/.next/static/media/favicon.2246eezznj2ab.ico +0 -0
- package/.next/static/media/fef07dbb0973bf53-s.3p2_lha1f2xer.woff2 +0 -0
- package/.next/static/rjdzHqzPw2GCNhDbjcu0-/_buildManifest.js +11 -0
- package/.next/static/rjdzHqzPw2GCNhDbjcu0-/_clientMiddlewareManifest.js +1 -0
- package/README.md +176 -4
- package/bin/pkgviz.ts +57 -29
- package/package.json +57 -36
- package/src/app/actions/audit.actions.ts +7 -49
- package/src/app/globals.css +0 -2
- package/src/app/layout.tsx +3 -2
- package/src/app/loading.tsx +8 -0
- package/src/app/page.tsx +16 -2
- package/src/app/utils/buildGraph.ts +99 -100
- package/src/app/utils/getParsedFileStructure.ts +128 -54
- package/src/app/utils/inspectParserLanguageAsync.ts +39 -0
- package/src/app/utils/markCyclicPackages.ts +45 -185
- package/src/app/utils/parser/cpp/parseCppFile.ts +68 -86
- package/src/app/utils/parser/delphi/parseFile.ts +36 -120
- package/src/app/utils/parser/java/findEntryPoint.ts +2 -1
- package/src/app/utils/parser/java/parseJavaFile.ts +33 -45
- package/src/app/utils/parser/kotlin/parseFile.ts +34 -87
- package/src/app/utils/parser/python/parseFile.ts +30 -100
- package/src/app/utils/parser/typescript/parseFile.ts +17 -52
- package/src/app/utils/selectParserLanguage.ts +39 -0
- package/src/cli/formatAuditRuleFailures.ts +21 -0
- package/src/cli/runAuditAsync.ts +41 -0
- package/src/components/Breadcrumb.tsx +5 -4
- package/src/components/ExportPanel.tsx +53 -0
- package/src/components/Header.tsx +1 -0
- package/src/components/Loader.tsx +8 -2
- package/src/components/ProjectLoadError.tsx +15 -0
- package/src/components/SettingsPanel.tsx +184 -0
- package/src/components/Switch.tsx +9 -17
- package/src/components/ThemeToggle.tsx +2 -1
- package/src/components/ToggleSwitch.tsx +36 -0
- package/src/components/sidebar/Sidebar.tsx +14 -0
- package/src/components/sidebar/SidebarBadge.tsx +25 -0
- package/src/components/sidebar/SidebarRow.tsx +14 -0
- package/src/components/sidebar/SidebarSection.tsx +16 -0
- package/src/components/sidebar/SidebarTabs.tsx +58 -0
- package/src/contexts/SettingsContext.tsx +19 -20
- package/src/features/audit/adapters/inbound/react/AuditRuleList.tsx +76 -0
- package/src/features/audit/adapters/inbound/react/AuditRulePanel.tsx +30 -0
- package/src/features/audit/adapters/inbound/react/CycleInspector.tsx +116 -0
- package/src/features/audit/adapters/inbound/react/CyclicDependenciesRuleDetails.tsx +124 -0
- package/src/features/audit/adapters/inbound/react/useCycleSelection.ts +47 -0
- package/src/features/audit/application/use-cases/createAuditFromSnapshot.ts +28 -0
- package/src/features/audit/application/use-cases/resolveSelectedCycleIds.ts +18 -0
- package/src/features/audit/composition/createAuditAsync.ts +11 -0
- package/src/features/audit/domain/evaluateAuditRules.ts +42 -0
- package/src/features/audit/domain/hasBlockingAuditRuleFailure.ts +6 -0
- package/src/features/audit/domain/resolveAuditConfiguration.ts +27 -0
- package/src/features/audit/utils/cycleVisualization.ts +86 -0
- package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeDependencyImportsAsync.ts +172 -0
- package/src/features/dependency-analysis/adapters/outbound/dependency-graph/analyzeTypeScriptImportsAsync.ts +6 -0
- package/src/features/graph-view/adapters/inbound/react/DependencyGraphView.tsx +184 -0
- package/src/features/graph-view/adapters/inbound/react/GraphZoomControls.tsx +48 -0
- package/src/features/graph-view/adapters/inbound/react/applyGraphInteractionPresentation.ts +35 -0
- package/src/features/graph-view/adapters/inbound/react/createGraphViewModel.ts +240 -0
- package/src/features/graph-view/adapters/inbound/react/createGraphViewStyles.ts +37 -0
- package/src/features/graph-view/adapters/inbound/react/useGraphFocus.ts +104 -0
- package/src/features/graph-view/adapters/inbound/react/useGraphInteractions.ts +50 -0
- package/src/features/graph-view/adapters/inbound/react/useGraphProjection.ts +71 -0
- package/src/features/graph-view/adapters/inbound/react/useGraphViewport.ts +48 -0
- package/src/features/graph-view/domain/getDependencyHighlightClasses.ts +39 -0
- package/src/features/graph-view/domain/reduceGraphInteraction.ts +23 -0
- package/src/features/graph-view/utils/createCompoundOpacityIndex.ts +38 -0
- package/src/features/graph-view/utils/projectVisibleGraph.ts +94 -0
- package/src/features/graph-view/utils/readNodeDefinitionId.ts +7 -0
- package/src/features/graph-view/utils/removeEmptyStructuralNodes.ts +27 -0
- package/src/features/project-analysis/adapters/outbound/filesystem/readProjectSnapshotAsync.ts +12 -0
- package/src/features/project-analysis/application/use-cases/createProjectSnapshotReader.ts +29 -0
- package/src/features/project-analysis/composition/loadProjectOverviewAsync.ts +14 -0
- package/src/features/project-analysis/composition/loadProjectSnapshotAsync.ts +12 -0
- package/src/features/project-tree/adapters/inbound/react/ProjectTreePanel.tsx +52 -0
- package/src/features/project-tree/adapters/inbound/react/useProjectTreeExpansion.ts +46 -0
- package/src/features/project-tree/application/use-cases/buildProjectTree.ts +61 -0
- package/src/features/project-tree/application/use-cases/resolveProjectTreeNavigation.ts +13 -0
- package/src/features/project-tree/utils/findProjectTreeNode.ts +14 -0
- package/src/features/project-tree/utils/findProjectTreeNodeByGraphPackage.ts +21 -0
- package/src/features/project-tree/utils/getProjectTreeAncestorIds.ts +26 -0
- package/src/features/settings/utils/readSettingsEnvironment.ts +53 -0
- package/src/i18n/en.ts +21 -2
- package/src/i18n/i18n.ts +2 -3
- package/src/layouts/breadthfirst/style.ts +1 -0
- package/src/layouts/circle/style.ts +1 -0
- package/src/layouts/concentric/style.ts +1 -0
- package/src/layouts/elk/layout.ts +1 -3
- package/src/layouts/elk/style.ts +1 -0
- package/src/layouts/getWeightBuckets.ts +3 -1
- package/src/layouts/grid/style.ts +1 -0
- package/src/layouts/index.ts +0 -4
- package/src/layouts/style.ts +172 -25
- package/src/screens/home/Home.tsx +73 -25
- package/src/screens/home/HomeGraph.tsx +43 -0
- package/src/screens/home/HomeSidebar.tsx +129 -0
- package/src/shared/types/index.ts +0 -9
- package/src/shared/utils/getProjectName.ts +4 -1
- package/src/shared/utils/parseProjectPath.ts +1 -0
- package/src/shared/utils/toPosix.ts +1 -1
- package/src/types/audit.ts +76 -0
- package/src/types/auditVisualization.ts +22 -0
- package/src/types/graphInteraction.ts +9 -0
- package/src/types/parserSelection.ts +11 -0
- package/src/types/projectAnalysis.ts +20 -0
- package/src/types/projectAnalysisActionResult.ts +2 -0
- package/src/types/projectTree.ts +7 -0
- package/src/utils/filter/filterByPackagePrefix.ts +25 -7
- package/src/utils/filter/filterEmptyPackages.ts +28 -29
- package/src/utils/filter/filterSubPackagesFromDepth.ts +20 -17
- package/src/utils/filter/filterVendorPackages.ts +1 -1
- package/src/utils/filter/isIntrinsicGraphNode.ts +8 -0
- package/src/utils/filter/toggleCompoundNodes.ts +41 -31
- package/src/utils/runProjectAnalysisActionAsync.ts +14 -0
- package/tsconfig.json +11 -3
- package/.next/app-build-manifest.json +0 -29
- package/.next/cache/.previewinfo +0 -1
- package/.next/cache/.rscinfo +0 -1
- package/.next/cache/.tsbuildinfo +0 -1
- package/.next/cache/chrome-devtools-workspace-uuid +0 -1
- package/.next/cache/eslint/.cache_6t30dc +0 -1
- package/.next/cache/webpack/client-production/0.pack +0 -4
- package/.next/cache/webpack/client-production/1.pack +0 -0
- package/.next/cache/webpack/client-production/10.pack +0 -0
- package/.next/cache/webpack/client-production/11.pack +0 -0
- package/.next/cache/webpack/client-production/12.pack +0 -0
- package/.next/cache/webpack/client-production/13.pack +0 -0
- package/.next/cache/webpack/client-production/14.pack +0 -0
- package/.next/cache/webpack/client-production/15.pack +0 -0
- package/.next/cache/webpack/client-production/16.pack +0 -0
- package/.next/cache/webpack/client-production/2.pack +0 -0
- package/.next/cache/webpack/client-production/3.pack +0 -0
- package/.next/cache/webpack/client-production/4.pack +0 -0
- package/.next/cache/webpack/client-production/5.pack +0 -0
- package/.next/cache/webpack/client-production/6.pack +0 -0
- package/.next/cache/webpack/client-production/7.pack +0 -0
- package/.next/cache/webpack/client-production/8.pack +0 -0
- package/.next/cache/webpack/client-production/9.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack +0 -0
- package/.next/cache/webpack/client-production/index.pack.old +0 -0
- package/.next/cache/webpack/edge-server-production/0.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack +0 -0
- package/.next/cache/webpack/edge-server-production/index.pack.old +0 -0
- package/.next/cache/webpack/server-production/0.pack +0 -0
- package/.next/cache/webpack/server-production/1.pack +0 -0
- package/.next/cache/webpack/server-production/10.pack +0 -4
- package/.next/cache/webpack/server-production/11.pack +0 -0
- package/.next/cache/webpack/server-production/12.pack +0 -0
- package/.next/cache/webpack/server-production/13.pack +0 -0
- package/.next/cache/webpack/server-production/14.pack +0 -0
- package/.next/cache/webpack/server-production/15.pack +0 -0
- package/.next/cache/webpack/server-production/16.pack +0 -0
- package/.next/cache/webpack/server-production/17.pack +0 -0
- package/.next/cache/webpack/server-production/18.pack +0 -4
- package/.next/cache/webpack/server-production/2.pack +0 -0
- package/.next/cache/webpack/server-production/3.pack +0 -0
- package/.next/cache/webpack/server-production/4.pack +0 -0
- package/.next/cache/webpack/server-production/5.pack +0 -0
- package/.next/cache/webpack/server-production/6.pack +0 -0
- package/.next/cache/webpack/server-production/7.pack +0 -0
- package/.next/cache/webpack/server-production/8.pack +0 -0
- package/.next/cache/webpack/server-production/9.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack +0 -0
- package/.next/cache/webpack/server-production/index.pack.old +0 -0
- package/.next/diagnostics/build-diagnostics.json +0 -6
- package/.next/diagnostics/framework.json +0 -1
- package/.next/server/app/index.html +0 -1
- package/.next/server/app/index.meta +0 -7
- package/.next/server/app/index.rsc +0 -20
- package/.next/server/chunks/548.js +0 -6
- package/.next/server/chunks/610.js +0 -7
- package/.next/server/chunks/985.js +0 -22
- package/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/.next/server/pages/_app.js +0 -1
- package/.next/server/pages/_app.js.nft.json +0 -1
- package/.next/server/pages/_document.js +0 -1
- package/.next/server/pages/_document.js.nft.json +0 -1
- package/.next/server/pages/_error.js +0 -19
- package/.next/server/pages/_error.js.nft.json +0 -1
- package/.next/server/webpack-runtime.js +0 -1
- package/.next/static/_YC2p40ZiYT2Gcw-h_tjC/_buildManifest.js +0 -1
- package/.next/static/chunks/4bd1b696-cf72ae8a39fa05aa.js +0 -1
- package/.next/static/chunks/680-55ad17895c8fb70b.js +0 -1
- package/.next/static/chunks/90542734-29e255269788f1bd.js +0 -1
- package/.next/static/chunks/91dbc596-b9cdccd3f5cba95d.js +0 -1
- package/.next/static/chunks/964-b440f7af22c41ca5.js +0 -1
- package/.next/static/chunks/app/_not-found/page-11e4fea8e290f304.js +0 -1
- package/.next/static/chunks/app/layout-8aae7fba5ed8afb3.js +0 -1
- package/.next/static/chunks/app/page-91450b1230da8bca.js +0 -1
- package/.next/static/chunks/framework-bc35dade6ff9684e.js +0 -1
- package/.next/static/chunks/main-9e86d333c1e02dd1.js +0 -1
- package/.next/static/chunks/main-app-69a9ff75ff3465ca.js +0 -1
- package/.next/static/chunks/pages/_app-0a0020ddd67f79cf.js +0 -1
- package/.next/static/chunks/pages/_error-03529f2c21436739.js +0 -1
- package/.next/static/chunks/webpack-7adfafc806738767.js +0 -1
- package/.next/static/css/ec31779168107a11.css +0 -3
- package/.next/static/media/4cf2300e9c8272f7-s.p.woff2 +0 -0
- package/.next/static/media/747892c23ea88013-s.woff2 +0 -0
- package/.next/static/media/8d697b304b401681-s.woff2 +0 -0
- package/.next/static/media/93f479601ee12b01-s.p.woff2 +0 -0
- package/.next/static/media/9610d9e46709d722-s.woff2 +0 -0
- package/.next/static/media/ba015fad6dcf6784-s.woff2 +0 -0
- package/.next/trace +0 -2
- package/.next/types/app/layout.ts +0 -84
- package/.next/types/app/page.ts +0 -84
- package/.next/types/cache-life.d.ts +0 -141
- package/.next/types/package.json +0 -1
- package/src/app/actions/graph.actions.ts +0 -25
- package/src/app/utils/parser/cpp/extractCppPackageFromImport.ts +0 -18
- package/src/app/utils/parser/delphi/extractPackageFromImport.ts +0 -21
- package/src/app/utils/parser/java/extractJavaPackageFromImport.ts +0 -39
- package/src/app/utils/parser/java/getIntrinsicPackagesRecursive.ts +0 -33
- package/src/app/utils/parser/kotlin/extractPackageFromImport.ts +0 -19
- package/src/app/utils/parser/python/extractPythonPackageFromImport.ts +0 -18
- package/src/app/utils/parser/typescript/extractTypeScriptPackageFromImport.ts +0 -18
- package/src/components/Cytoscape.tsx +0 -23
- package/src/components/Setting.tsx +0 -17
- package/src/components/Settings.tsx +0 -189
- package/src/components/ZoomInput.tsx +0 -94
- package/src/components/useCytoscape.ts +0 -343
- package/src/layouts/getLayoutStyle.ts +0 -19
- package/src/shared/utils/detectLanguage.ts +0 -255
- package/src/shared/utils/getJsonAsync.ts +0 -13
- package/src/shared/utils/parseEnv.ts +0 -91
- package/src/store/useLocalStorage.ts +0 -29
- package/src/utils/hasChildren.ts +0 -7
- /package/.next/{react-loadable-manifest.json → server/app/_global-error/page/react-loadable-manifest.json} +0 -0
- /package/.next/static/chunks/{polyfills-42372ed130431b0a.js → 0cz1d0mv5g_q7.js} +0 -0
- /package/.next/static/{_YC2p40ZiYT2Gcw-h_tjC → 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
|
-
}
|