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
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ProjectTreeNode } from '@/types/projectTree';
|
|
2
|
+
|
|
3
|
+
/*** Finds the deepest directory representing a graph package, falling back to a matching file. */
|
|
4
|
+
export function findProjectTreeNodeByGraphPackage(
|
|
5
|
+
nodes: readonly ProjectTreeNode[],
|
|
6
|
+
graphPackage: string
|
|
7
|
+
): ProjectTreeNode | null {
|
|
8
|
+
const matches = collectProjectTreePackageMatches(nodes, graphPackage);
|
|
9
|
+
return matches.find(node => node.kind === 'directory') ?? matches.at(0) ?? null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/*** Collects package matches depth-first so nested directories outrank their ancestors. */
|
|
13
|
+
function collectProjectTreePackageMatches(
|
|
14
|
+
nodes: readonly ProjectTreeNode[],
|
|
15
|
+
graphPackage: string
|
|
16
|
+
): readonly ProjectTreeNode[] {
|
|
17
|
+
return nodes.flatMap(node => [
|
|
18
|
+
...(node.children ? collectProjectTreePackageMatches(node.children, graphPackage) : []),
|
|
19
|
+
...(node.graphPackage === graphPackage ? [node] : []),
|
|
20
|
+
]);
|
|
21
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { ProjectTreeNode } from '@/types/projectTree';
|
|
2
|
+
|
|
3
|
+
/*** Returns every directory id that must be expanded to reveal one tree node. */
|
|
4
|
+
export function getProjectTreeAncestorIds(
|
|
5
|
+
nodes: readonly ProjectTreeNode[],
|
|
6
|
+
targetId: string
|
|
7
|
+
): readonly string[] {
|
|
8
|
+
return findProjectTreeAncestorIds(nodes, targetId, []) ?? [];
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/*** Finds one target recursively while carrying its directory ancestry. */
|
|
12
|
+
function findProjectTreeAncestorIds(
|
|
13
|
+
nodes: readonly ProjectTreeNode[],
|
|
14
|
+
targetId: string,
|
|
15
|
+
ancestors: readonly string[]
|
|
16
|
+
): readonly string[] | null {
|
|
17
|
+
for (const node of nodes) {
|
|
18
|
+
if (node.id === targetId) return ancestors;
|
|
19
|
+
if (!node.children) continue;
|
|
20
|
+
|
|
21
|
+
const match = findProjectTreeAncestorIds(node.children, targetId, [...ancestors, node.id]);
|
|
22
|
+
if (match !== null) return match;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { readEnvBoolean, readEnvNumber, readEnvString } from '@ankhorage/utility/node/env';
|
|
2
|
+
import type { LayoutOptions } from 'cytoscape';
|
|
3
|
+
|
|
4
|
+
/*** Reads and validates PKGViz viewer defaults from public settings environment variables. */
|
|
5
|
+
export function readSettingsEnvironment(): SettingsEnvironment {
|
|
6
|
+
const environment = {
|
|
7
|
+
NEXT_PUBLIC_SETTINGS_SHOW_CYCLES: process.env.NEXT_PUBLIC_SETTINGS_SHOW_CYCLES,
|
|
8
|
+
NEXT_PUBLIC_SETTINGS_LAYOUT: process.env.NEXT_PUBLIC_SETTINGS_LAYOUT,
|
|
9
|
+
NEXT_PUBLIC_SETTINGS_LAYOUT_SPACING: process.env.NEXT_PUBLIC_SETTINGS_LAYOUT_SPACING,
|
|
10
|
+
NEXT_PUBLIC_SETTINGS_SHOW_COMPOUNDNODES: process.env.NEXT_PUBLIC_SETTINGS_SHOW_COMPOUNDNODES,
|
|
11
|
+
NEXT_PUBLIC_SETTINGS_SHOW_VENDORPACKAGES: process.env.NEXT_PUBLIC_SETTINGS_SHOW_VENDORPACKAGES,
|
|
12
|
+
NEXT_PUBLIC_SETTINGS_SUBPACKAGE_DEPTH: process.env.NEXT_PUBLIC_SETTINGS_SUBPACKAGE_DEPTH,
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
const layout = readEnvString('NEXT_PUBLIC_SETTINGS_LAYOUT', environment);
|
|
16
|
+
const layoutSpacing = readEnvNumber('NEXT_PUBLIC_SETTINGS_LAYOUT_SPACING', environment);
|
|
17
|
+
const subPackageDepth = readEnvNumber('NEXT_PUBLIC_SETTINGS_SUBPACKAGE_DEPTH', environment);
|
|
18
|
+
|
|
19
|
+
return {
|
|
20
|
+
showCycles: readEnvBoolean('NEXT_PUBLIC_SETTINGS_SHOW_CYCLES', environment) ?? false,
|
|
21
|
+
cytoscapeLayout: isSupportedLayout(layout) ? layout : 'concentric',
|
|
22
|
+
cytoscapeLayoutSpacing:
|
|
23
|
+
layoutSpacing !== undefined && layoutSpacing >= 0.1 && layoutSpacing <= 1 ? layoutSpacing : 1,
|
|
24
|
+
showCompoundNodes:
|
|
25
|
+
readEnvBoolean('NEXT_PUBLIC_SETTINGS_SHOW_COMPOUNDNODES', environment) ?? true,
|
|
26
|
+
showVendorPackages:
|
|
27
|
+
readEnvBoolean('NEXT_PUBLIC_SETTINGS_SHOW_VENDORPACKAGES', environment) ?? false,
|
|
28
|
+
subPackageDepth:
|
|
29
|
+
subPackageDepth !== undefined && Number.isInteger(subPackageDepth) && subPackageDepth >= 1
|
|
30
|
+
? subPackageDepth
|
|
31
|
+
: 1,
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/*** Determines whether an environment value names a supported Cytoscape layout. */
|
|
36
|
+
function isSupportedLayout(value: string | undefined): value is LayoutOptions['name'] {
|
|
37
|
+
return (
|
|
38
|
+
value === 'breadthfirst' ||
|
|
39
|
+
value === 'circle' ||
|
|
40
|
+
value === 'concentric' ||
|
|
41
|
+
value === 'elk' ||
|
|
42
|
+
value === 'grid'
|
|
43
|
+
);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
interface SettingsEnvironment {
|
|
47
|
+
readonly showCycles: boolean;
|
|
48
|
+
readonly cytoscapeLayout: LayoutOptions['name'];
|
|
49
|
+
readonly cytoscapeLayoutSpacing: number;
|
|
50
|
+
readonly showCompoundNodes: boolean;
|
|
51
|
+
readonly showVendorPackages: boolean;
|
|
52
|
+
readonly subPackageDepth: number;
|
|
53
|
+
}
|
package/src/i18n/en.ts
CHANGED
|
@@ -7,15 +7,34 @@ const en: ILanguage = {
|
|
|
7
7
|
|
|
8
8
|
// Settings
|
|
9
9
|
'settings.title': 'Settings',
|
|
10
|
+
'settings.tree': 'Tree',
|
|
11
|
+
'settings.rules': 'Rules',
|
|
12
|
+
'settings.export': 'Export',
|
|
13
|
+
'sidebar.tools': 'Sidebar tools',
|
|
10
14
|
'settings.showCompoundNodes': 'Show Compound Nodes',
|
|
11
15
|
'settings.showVendorPackages': 'Show Vendor',
|
|
12
16
|
'settings.subPackageDepth': 'Subpackage depth',
|
|
13
|
-
'settings.audit': 'Audit',
|
|
14
|
-
'settings.download': 'Download',
|
|
15
17
|
'settings.layout': 'Layout',
|
|
16
18
|
'settings.layoutSpacing': 'Layout Spacing',
|
|
17
19
|
'settings.filter': 'Filter',
|
|
18
20
|
|
|
21
|
+
// Audit
|
|
22
|
+
'audit.rules': 'Audit rules',
|
|
23
|
+
'audit.loading': 'Loading audit…',
|
|
24
|
+
'audit.loadError': 'Unable to load audit details.',
|
|
25
|
+
'audit.noRules': 'No audit rules are enabled.',
|
|
26
|
+
'audit.cycle': 'Cycle',
|
|
27
|
+
'audit.cycles': 'cycles',
|
|
28
|
+
'audit.findings': 'findings',
|
|
29
|
+
'audit.imports': 'imports',
|
|
30
|
+
'audit.cyclePath': 'Cycle path',
|
|
31
|
+
'audit.dependencyEvidence': 'Dependency evidence',
|
|
32
|
+
'audit.packages': 'packages',
|
|
33
|
+
'audit.dependencyEdges': 'dependency edges',
|
|
34
|
+
'audit.noEvidence': 'No source/import evidence available.',
|
|
35
|
+
'audit.closeInspector': 'Close cycle inspector',
|
|
36
|
+
'audit.rule.cyclicDependencies': 'Cyclic Dependencies',
|
|
37
|
+
|
|
19
38
|
// Layouts
|
|
20
39
|
breadthfirst: 'Breadthfirst',
|
|
21
40
|
circle: 'Circle',
|
package/src/i18n/i18n.ts
CHANGED
|
@@ -3,10 +3,9 @@ import en from '@/i18n/en';
|
|
|
3
3
|
const languages = { en };
|
|
4
4
|
const activeLang = languages.en;
|
|
5
5
|
|
|
6
|
+
/*** Returns the localized string for a translation key. */
|
|
6
7
|
export function t(term: string) {
|
|
7
8
|
return activeLang[term] || `{${term}}`;
|
|
8
9
|
}
|
|
9
10
|
|
|
10
|
-
export
|
|
11
|
-
readonly [key: string]: string;
|
|
12
|
-
}
|
|
11
|
+
export type ILanguage = Readonly<Record<string, string>>;
|
package/src/layouts/elk/style.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ElementsDefinition } from 'cytoscape';
|
|
2
2
|
|
|
3
|
+
/*** Computes edge-weight thresholds and bucket counts. */
|
|
3
4
|
export function getWeightBuckets(
|
|
4
5
|
categoryCount: number,
|
|
5
6
|
algorithm: 'linear' | 'log' | 'quantile' = 'linear',
|
|
@@ -49,7 +50,8 @@ export function getWeightBuckets(
|
|
|
49
50
|
};
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
|
|
53
|
+
/*** Returns the largest edge weight in the graph. */
|
|
54
|
+
function getMaxEdgeWeight(filteredElements: ElementsDefinition) {
|
|
53
55
|
return (
|
|
54
56
|
filteredElements?.edges.reduce((max, edge) => {
|
|
55
57
|
return edge.data.weight > max ? edge.data.weight : max;
|
package/src/layouts/index.ts
CHANGED
|
@@ -1,14 +1,10 @@
|
|
|
1
1
|
export { layout as breadthfirstLayout } from '@/layouts/breadthfirst/layout';
|
|
2
2
|
export { getStyle as getBreadthfirstStyle } from '@/layouts/breadthfirst/style';
|
|
3
|
-
|
|
4
3
|
export { layout as circleLayout } from '@/layouts/circle/layout';
|
|
5
4
|
export { getStyle as getCircleStyle } from '@/layouts/circle/style';
|
|
6
|
-
|
|
7
5
|
export { layout as concentricLayout } from '@/layouts/concentric/layout';
|
|
8
6
|
export { getStyle as getConcentricStyle } from '@/layouts/concentric/style';
|
|
9
|
-
|
|
10
7
|
export { layout as elkLayout } from '@/layouts/elk/layout';
|
|
11
8
|
export { getStyle as getElkStyle } from '@/layouts/elk/style';
|
|
12
|
-
|
|
13
9
|
export { layout as gridLayout } from '@/layouts/grid/layout';
|
|
14
10
|
export { getStyle as getGridStyle } from '@/layouts/grid/style';
|
package/src/layouts/style.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import type { ElementsDefinition,
|
|
1
|
+
import type { ElementsDefinition, StylesheetJson } from 'cytoscape';
|
|
2
2
|
|
|
3
|
+
import { createCompoundOpacityIndex } from '@/features/graph-view/utils/createCompoundOpacityIndex';
|
|
3
4
|
import { getWeightBuckets } from '@/layouts/getWeightBuckets';
|
|
4
5
|
|
|
5
6
|
export type ThemeKey = 'dark' | 'light';
|
|
@@ -7,7 +8,6 @@ export type ThemeKey = 'dark' | 'light';
|
|
|
7
8
|
const palette = {
|
|
8
9
|
light: {
|
|
9
10
|
canvasBg: '#ffffff',
|
|
10
|
-
// edge: '#9E9E9E',
|
|
11
11
|
edge: '#000',
|
|
12
12
|
weightXs: '#000',
|
|
13
13
|
weightMd: '#000',
|
|
@@ -18,6 +18,7 @@ const palette = {
|
|
|
18
18
|
nodeBorderVendor: '#E2D5FF',
|
|
19
19
|
nodeBgVendor: '#D1C4FF',
|
|
20
20
|
nodeText: '#0B5FFF',
|
|
21
|
+
compoundBg: '#7892B3',
|
|
21
22
|
|
|
22
23
|
selectedFill: '#0B5FFF',
|
|
23
24
|
selectedFillVendor: '#a025aa',
|
|
@@ -36,6 +37,7 @@ const palette = {
|
|
|
36
37
|
nodeBorder: '#2A3A4A',
|
|
37
38
|
nodeBorderVendor: '#351542',
|
|
38
39
|
nodeText: '#E8F0FF',
|
|
40
|
+
compoundBg: '#A9BCD5',
|
|
39
41
|
|
|
40
42
|
selectedFill: '#2E6FFF',
|
|
41
43
|
selectedFillVendor: '#4E25AA',
|
|
@@ -44,12 +46,55 @@ const palette = {
|
|
|
44
46
|
},
|
|
45
47
|
} as const;
|
|
46
48
|
|
|
49
|
+
/*** Returns the canvas background for the active theme. */
|
|
47
50
|
export const getCanvasBg = (theme: ThemeKey) => palette[theme].canvasBg;
|
|
48
51
|
|
|
52
|
+
/*** Builds the shared Cytoscape styles for the active theme. */
|
|
49
53
|
export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey): StylesheetJson {
|
|
50
54
|
const colors = palette[theme];
|
|
51
55
|
const { thresholds } = getWeightBuckets(3, 'linear', filteredElements);
|
|
52
56
|
|
|
57
|
+
return [
|
|
58
|
+
...getNodeBaseStyles(colors),
|
|
59
|
+
...getNodeInteractionStyles(colors),
|
|
60
|
+
...getNodeStateStyles(colors),
|
|
61
|
+
...getCompoundStyles(colors),
|
|
62
|
+
...getCompoundOpacityStyles(filteredElements),
|
|
63
|
+
...getEdgeBaseStyles(colors),
|
|
64
|
+
...getEdgeWeightStyles(colors, thresholds),
|
|
65
|
+
...getCycleEdgeStyles(colors),
|
|
66
|
+
];
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
type Palette = (typeof palette)[ThemeKey];
|
|
70
|
+
|
|
71
|
+
/***
|
|
72
|
+
* Shows leaf neighborhoods without changing layout geometry or dimming compound descendants.
|
|
73
|
+
* @performance Use paint-only interaction styles; border size, labels and dimensions stay stable.
|
|
74
|
+
*/
|
|
75
|
+
function getNodeInteractionStyles(colors: Palette): StylesheetJson {
|
|
76
|
+
return [
|
|
77
|
+
{ selector: 'node:childless.hushed', style: { opacity: 0.2 } },
|
|
78
|
+
{
|
|
79
|
+
selector: 'node.highlight-outgoer, node.highlight-incomer',
|
|
80
|
+
style: { 'border-color': colors.selectedRing, opacity: 1 },
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
selector: 'node:childless.highlight',
|
|
84
|
+
style: { 'background-color': colors.selectedFill, color: colors.selectedText, opacity: 1 },
|
|
85
|
+
},
|
|
86
|
+
];
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/***
|
|
90
|
+
* Maps prepared node presentation data without per-element style callbacks.
|
|
91
|
+
* @performance
|
|
92
|
+
* Preserve data(label): createGraphViewModel prepares labels outside Cytoscape style recalculation.
|
|
93
|
+
* ZORA owns measured label width. Keep height independent of the previous rendered height, otherwise repeated
|
|
94
|
+
* style updates can change geometry and trigger further layout work. The style regression tests
|
|
95
|
+
* cover stable dimensions across theme changes and updates to prepared label data.
|
|
96
|
+
*/
|
|
97
|
+
function getNodeBaseStyles(colors: Palette): StylesheetJson {
|
|
53
98
|
return [
|
|
54
99
|
{
|
|
55
100
|
selector: 'node',
|
|
@@ -58,16 +103,12 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
58
103
|
'background-color': colors.nodeBg,
|
|
59
104
|
'border-color': colors.nodeBorder,
|
|
60
105
|
color: colors.nodeText,
|
|
61
|
-
label: 'data(
|
|
106
|
+
label: 'data(label)',
|
|
62
107
|
'text-valign': 'center',
|
|
63
108
|
'text-halign': 'center',
|
|
64
|
-
width:
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
height: (node: NodeSingular) => {
|
|
68
|
-
return node.height() / 2 + 10;
|
|
69
|
-
},
|
|
70
|
-
padding: '8px 8px',
|
|
109
|
+
width: 24,
|
|
110
|
+
height: 24,
|
|
111
|
+
padding: '12px',
|
|
71
112
|
'border-width': 1,
|
|
72
113
|
'font-size': '14px',
|
|
73
114
|
'overlay-opacity': 0, // avoid gray overlay
|
|
@@ -79,14 +120,36 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
79
120
|
'background-color': colors.nodeBgVendor,
|
|
80
121
|
},
|
|
81
122
|
},
|
|
82
|
-
|
|
123
|
+
];
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/***
|
|
127
|
+
* Preserves selected-node and audit-cycle presentation.
|
|
128
|
+
* @performance Selection uses an outline: changing border width changes layout dimensions.
|
|
129
|
+
* Audit overlays retain their existing geometry and remain separate from transient interactions.
|
|
130
|
+
*/
|
|
131
|
+
function getNodeStateStyles(colors: Palette): StylesheetJson {
|
|
132
|
+
return [
|
|
133
|
+
{
|
|
134
|
+
selector: 'node.auditCycle',
|
|
135
|
+
style: {
|
|
136
|
+
'border-color': 'data(auditCycleColor)',
|
|
137
|
+
'border-width': 5,
|
|
138
|
+
opacity: 1,
|
|
139
|
+
'underlay-color': 'data(auditCycleColor)',
|
|
140
|
+
'underlay-opacity': 0.18,
|
|
141
|
+
'underlay-padding': 4,
|
|
142
|
+
'z-index': 999,
|
|
143
|
+
},
|
|
144
|
+
},
|
|
83
145
|
{ selector: 'node.isParent', style: { 'font-weight': 'bold' } },
|
|
84
146
|
{
|
|
85
147
|
selector: 'node:selected',
|
|
86
148
|
style: {
|
|
87
149
|
'background-color': colors.selectedFill,
|
|
88
150
|
'border-color': colors.selectedRing,
|
|
89
|
-
'
|
|
151
|
+
'outline-color': colors.selectedRing,
|
|
152
|
+
'outline-width': 2,
|
|
90
153
|
color: colors.selectedText,
|
|
91
154
|
'background-opacity': 1,
|
|
92
155
|
opacity: 1,
|
|
@@ -97,23 +160,35 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
97
160
|
selector: 'node.isVendor:selected',
|
|
98
161
|
style: { 'background-color': colors.selectedFillVendor },
|
|
99
162
|
},
|
|
163
|
+
];
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
/***
|
|
167
|
+
* Shows softly tinted compound boundaries with bounded, prepared nested-depth opacity.
|
|
168
|
+
* @performance Keep grouping paint-only; do not add nested DOM surfaces or extra graph elements.
|
|
169
|
+
*/
|
|
170
|
+
function getCompoundStyles(colors: Palette): StylesheetJson {
|
|
171
|
+
return [
|
|
100
172
|
{
|
|
101
173
|
selector: 'node:parent, node:parent:selected',
|
|
102
174
|
style: {
|
|
103
|
-
'background-opacity': 0.
|
|
104
|
-
'background-color': colors.
|
|
175
|
+
'background-opacity': 0.04,
|
|
176
|
+
'background-color': colors.compoundBg,
|
|
105
177
|
color: colors.nodeText,
|
|
106
|
-
'border-width':
|
|
178
|
+
'border-width': 1,
|
|
179
|
+
'border-opacity': 0.35,
|
|
107
180
|
'border-color': colors.nodeBorder,
|
|
108
181
|
'text-valign': 'top',
|
|
109
182
|
'text-margin-y': -5,
|
|
110
|
-
padding: '
|
|
111
|
-
'
|
|
183
|
+
padding: '16px',
|
|
184
|
+
'text-background-color': colors.canvasBg,
|
|
185
|
+
'text-background-opacity': 0.85,
|
|
186
|
+
'text-background-padding': '3px',
|
|
112
187
|
'text-halign': 'center',
|
|
113
188
|
'font-size': 14,
|
|
114
189
|
'font-weight': 'bold',
|
|
115
190
|
'font-style': 'italic',
|
|
116
|
-
label: 'data(
|
|
191
|
+
label: 'data(label)',
|
|
117
192
|
},
|
|
118
193
|
},
|
|
119
194
|
{
|
|
@@ -123,6 +198,50 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
123
198
|
'border-color': colors.nodeBorderVendor,
|
|
124
199
|
},
|
|
125
200
|
},
|
|
201
|
+
{
|
|
202
|
+
selector: 'node:parent.auditCycle, node:parent.auditCycle:selected',
|
|
203
|
+
style: {
|
|
204
|
+
'underlay-opacity': 0,
|
|
205
|
+
'border-color': 'data(auditCycleColor)',
|
|
206
|
+
'border-opacity': 0.8,
|
|
207
|
+
'outline-color': 'data(auditCycleColor)',
|
|
208
|
+
'outline-width': 2,
|
|
209
|
+
color: 'data(auditCycleColor)',
|
|
210
|
+
},
|
|
211
|
+
},
|
|
212
|
+
];
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/***
|
|
216
|
+
* Emits one numeric paint rule per visible depth, including depths created by detached endpoints.
|
|
217
|
+
* @performance Bound stylesheet size by hierarchy depth, not node count; no style callbacks.
|
|
218
|
+
*/
|
|
219
|
+
function getCompoundOpacityStyles(elements: ElementsDefinition): StylesheetJson {
|
|
220
|
+
const ids = new Set(elements.nodes.map(node => node.data.id));
|
|
221
|
+
const parents = new Map(
|
|
222
|
+
elements.nodes.flatMap(node => {
|
|
223
|
+
const { id, parent } = node.data;
|
|
224
|
+
return typeof id === 'string' && typeof parent === 'string' && ids.has(parent)
|
|
225
|
+
? [[id, parent] as const]
|
|
226
|
+
: [];
|
|
227
|
+
})
|
|
228
|
+
);
|
|
229
|
+
const opacities = createCompoundOpacityIndex(parents, new Set());
|
|
230
|
+
return [...new Set(opacities.values())].map(opacity => ({
|
|
231
|
+
selector: `node:parent[compoundFillOpacity = ${opacity}]`,
|
|
232
|
+
style: { 'background-opacity': opacity },
|
|
233
|
+
}));
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/***
|
|
237
|
+
* Keeps ordinary directed edges opaque to avoid the extra rendering cost of translucent arrows.
|
|
238
|
+
* @performance
|
|
239
|
+
* Hushed edges are an intentional interaction state, not the base rendering policy. Retain arrows
|
|
240
|
+
* and loop-capable routing: cheaper edge styles must not silently remove dependency direction or
|
|
241
|
+
* lifted self-loops. Measure and discuss those visual tradeoffs before changing this baseline.
|
|
242
|
+
*/
|
|
243
|
+
function getEdgeBaseStyles(colors: Palette): StylesheetJson {
|
|
244
|
+
return [
|
|
126
245
|
{
|
|
127
246
|
selector: 'edge',
|
|
128
247
|
style: {
|
|
@@ -131,7 +250,10 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
131
250
|
'target-arrow-shape': 'chevron',
|
|
132
251
|
'target-arrow-fill': 'filled',
|
|
133
252
|
'line-color': colors.edge,
|
|
134
|
-
|
|
253
|
+
// Bezier routing keeps lifted self-loops renderable; line endpoints avoid invalid compound overlaps.
|
|
254
|
+
'curve-style': 'bezier',
|
|
255
|
+
'source-endpoint': 'outside-to-line',
|
|
256
|
+
'target-endpoint': 'outside-to-line',
|
|
135
257
|
opacity: 1,
|
|
136
258
|
'line-opacity': 1,
|
|
137
259
|
},
|
|
@@ -153,6 +275,12 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
153
275
|
'source-arrow-color': colors.weightXl,
|
|
154
276
|
},
|
|
155
277
|
},
|
|
278
|
+
];
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
/*** Applies the existing aggregate dependency-weight buckets. */
|
|
282
|
+
function getEdgeWeightStyles(colors: Palette, thresholds: readonly number[]): StylesheetJson {
|
|
283
|
+
return [
|
|
156
284
|
{ selector: 'edge[weight <= 1]', style: { label: '' } },
|
|
157
285
|
{
|
|
158
286
|
selector: `edge[weight > 1][weight <= ${thresholds[0]}]`,
|
|
@@ -179,13 +307,32 @@ export function getStyle(filteredElements: ElementsDefinition, theme: ThemeKey):
|
|
|
179
307
|
'target-arrow-color': colors.weightXl,
|
|
180
308
|
},
|
|
181
309
|
},
|
|
310
|
+
];
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
/*** Shows audit steps above compound content only for active cycle edges. */
|
|
314
|
+
function getCycleEdgeStyles(colors: Palette): StylesheetJson {
|
|
315
|
+
return [
|
|
182
316
|
{
|
|
183
|
-
selector: 'edge.
|
|
184
|
-
style: {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
317
|
+
selector: 'edge.auditCycle',
|
|
318
|
+
style: {
|
|
319
|
+
width: 6,
|
|
320
|
+
opacity: 1,
|
|
321
|
+
'line-opacity': 1,
|
|
322
|
+
'arrow-scale': 1.5,
|
|
323
|
+
'line-color': 'data(auditCycleColor)',
|
|
324
|
+
'target-arrow-color': 'data(auditCycleColor)',
|
|
325
|
+
color: 'data(auditCycleColor)',
|
|
326
|
+
label: 'data(auditCycleStep)',
|
|
327
|
+
'font-size': 12,
|
|
328
|
+
'font-weight': 'bold',
|
|
329
|
+
'text-background-color': colors.canvasBg,
|
|
330
|
+
'text-background-opacity': 0.9,
|
|
331
|
+
'text-background-padding': '3px',
|
|
332
|
+
'z-compound-depth': 'top',
|
|
333
|
+
'z-index-compare': 'manual',
|
|
334
|
+
'z-index': 9999,
|
|
335
|
+
},
|
|
189
336
|
},
|
|
190
337
|
];
|
|
191
338
|
}
|
|
@@ -1,48 +1,96 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import
|
|
2
|
+
import { useState } from 'react';
|
|
3
3
|
|
|
4
|
-
import { useEffect, useState } from 'react';
|
|
5
|
-
import { getGraphAction } from '@/app/actions/graph.actions';
|
|
6
4
|
import Breadcrumb from '@/components/Breadcrumb';
|
|
7
5
|
import Header from '@/components/Header';
|
|
8
|
-
import
|
|
9
|
-
import Settings from '@/components/Settings';
|
|
10
|
-
import { Cytoscape } from '@/components/Cytoscape';
|
|
6
|
+
import ProjectLoadError from '@/components/ProjectLoadError';
|
|
11
7
|
import { SettingsProvider } from '@/contexts/SettingsContext';
|
|
8
|
+
import { useCycleSelection } from '@/features/audit/adapters/inbound/react/useCycleSelection';
|
|
9
|
+
import { resolveProjectTreeNavigation } from '@/features/project-tree/application/use-cases/resolveProjectTreeNavigation';
|
|
10
|
+
import { findProjectTreeNodeByGraphPackage } from '@/features/project-tree/utils/findProjectTreeNodeByGraphPackage';
|
|
11
|
+
import { HomeGraph } from '@/screens/home/HomeGraph';
|
|
12
|
+
import { HomeSidebar } from '@/screens/home/HomeSidebar';
|
|
13
|
+
import type { Audit } from '@/types/audit';
|
|
14
|
+
import type { CycleInspection } from '@/types/auditVisualization';
|
|
15
|
+
import type { ProjectOverview } from '@/types/projectAnalysis';
|
|
16
|
+
import type { ProjectAnalysisActionResult } from '@/types/projectAnalysisActionResult';
|
|
17
|
+
import type { ProjectTreeNode } from '@/types/projectTree';
|
|
12
18
|
|
|
13
|
-
|
|
19
|
+
/*** Renders the PKGViz home screen and composes project navigation, diagnostics, and the graph. */
|
|
20
|
+
export default function HomeScreen({ project }: HomeScreenProps) {
|
|
14
21
|
const [currentPackage, setCurrentPackage] = useState<string>('');
|
|
15
|
-
const
|
|
22
|
+
const packageGraph = project.ok ? project.value.graph : null;
|
|
23
|
+
const projectTree = project.ok ? project.value.tree : [];
|
|
24
|
+
const [selectedTreeId, setSelectedTreeId] = useState<string | null>(null);
|
|
25
|
+
const auditEvaluation = project.ok ? project.value.evaluation : null;
|
|
26
|
+
const projectError = project.ok ? null : project.error;
|
|
27
|
+
const cycleSelection = useCycleSelection(auditEvaluation?.cyclicPackages ?? EMPTY_CYCLES);
|
|
28
|
+
const [cycleInspection, setCycleInspection] = useState<CycleInspection | null>(null);
|
|
16
29
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
30
|
+
/*** Navigates graph scope and mirrors the matching package selection in the project tree. */
|
|
31
|
+
const navigateToPackage = (path: string) => {
|
|
32
|
+
const packageName = normalizeGraphPackage(path);
|
|
33
|
+
const matchingTreeNode = findProjectTreeNodeByGraphPackage(projectTree, packageName);
|
|
34
|
+
setCurrentPackage(packageName);
|
|
35
|
+
setSelectedTreeId(matchingTreeNode?.id ?? null);
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
/*** Navigates only into packages with graph descendants; selecting a leaf keeps the current view. */
|
|
39
|
+
const selectProjectTreeNode = (node: ProjectTreeNode) => {
|
|
40
|
+
setSelectedTreeId(node.id);
|
|
41
|
+
setCurrentPackage(
|
|
42
|
+
resolveProjectTreeNavigation(
|
|
43
|
+
node,
|
|
44
|
+
packageGraph?.nodes.map(candidate => String(candidate.data.id ?? '')) ?? [],
|
|
45
|
+
currentPackage
|
|
46
|
+
)
|
|
47
|
+
);
|
|
48
|
+
};
|
|
22
49
|
|
|
23
50
|
return (
|
|
24
51
|
<>
|
|
25
52
|
<Header title="nav.packages">
|
|
26
|
-
<Breadcrumb
|
|
27
|
-
path={currentPackage.replace(/\./g, '/')}
|
|
28
|
-
onNavigate={(path: string) => setCurrentPackage(path.replace(/\//g, '.'))}
|
|
29
|
-
/>
|
|
53
|
+
<Breadcrumb path={currentPackage.replace(/\./g, '/')} onNavigate={navigateToPackage} />
|
|
30
54
|
</Header>
|
|
31
|
-
|
|
32
55
|
<SettingsProvider>
|
|
33
|
-
<main
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
56
|
+
<main
|
|
57
|
+
data-testid="main"
|
|
58
|
+
className="flex min-h-0 min-w-0 flex-1 flex-row overflow-hidden dark:bg-[#171717]"
|
|
59
|
+
>
|
|
60
|
+
<HomeSidebar
|
|
61
|
+
evaluation={auditEvaluation}
|
|
62
|
+
projectTree={projectTree}
|
|
63
|
+
selectedTreeId={selectedTreeId}
|
|
64
|
+
onProjectTreeSelect={selectProjectTreeNode}
|
|
65
|
+
cycleSelection={cycleSelection}
|
|
66
|
+
inspectedCycleId={cycleInspection?.id ?? null}
|
|
67
|
+
onCycleInspectionChange={setCycleInspection}
|
|
68
|
+
/>
|
|
69
|
+
{projectError ? (
|
|
70
|
+
<ProjectLoadError message={projectError} />
|
|
71
|
+
) : (
|
|
72
|
+
<HomeGraph
|
|
37
73
|
currentPackage={currentPackage}
|
|
38
|
-
|
|
74
|
+
cycleHighlights={cycleSelection.highlights}
|
|
75
|
+
cycleInspection={cycleInspection}
|
|
39
76
|
packageGraph={packageGraph}
|
|
77
|
+
setCurrentPackage={navigateToPackage}
|
|
78
|
+
onCloseInspection={() => setCycleInspection(null)}
|
|
40
79
|
/>
|
|
41
|
-
) : (
|
|
42
|
-
<Loader />
|
|
43
80
|
)}
|
|
44
81
|
</main>
|
|
45
82
|
</SettingsProvider>
|
|
46
83
|
</>
|
|
47
84
|
);
|
|
48
85
|
}
|
|
86
|
+
|
|
87
|
+
const EMPTY_CYCLES: NonNullable<Audit['evaluation']>['cyclicPackages'] = [];
|
|
88
|
+
|
|
89
|
+
interface HomeScreenProps {
|
|
90
|
+
readonly project: ProjectAnalysisActionResult<ProjectOverview>;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
/*** Normalizes graph navigation paths to the package-id representation used by Cytoscape. */
|
|
94
|
+
function normalizeGraphPackage(path: string): string {
|
|
95
|
+
return path.replaceAll('/', '.').replace(/^\.+|\.+$/g, '');
|
|
96
|
+
}
|