codebase-onboarder 0.6.0 → 0.7.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/README.md +174 -46
- package/bin/build-if-source.js +23 -0
- package/cli/commands.d.ts +26 -0
- package/cli/commands.js +836 -811
- package/cli/commands.js.map +1 -0
- package/cli/explorer/advanced.d.ts +14 -0
- package/cli/explorer/advanced.js +321 -329
- package/cli/explorer/advanced.js.map +1 -0
- package/cli/explorer/app.d.ts +1 -0
- package/cli/explorer/app.js +384 -313
- package/cli/explorer/app.js.map +1 -0
- package/cli/explorer/assistant.d.ts +9 -0
- package/cli/explorer/assistant.js +58 -0
- package/cli/explorer/assistant.js.map +1 -0
- package/cli/explorer/commands.d.ts +17 -0
- package/cli/explorer/commands.js +368 -302
- package/cli/explorer/commands.js.map +1 -0
- package/cli/explorer/featureViews.d.ts +124 -0
- package/cli/explorer/featureViews.js +179 -0
- package/cli/explorer/featureViews.js.map +1 -0
- package/cli/explorer/github.d.ts +21 -0
- package/cli/explorer/github.js +42 -44
- package/cli/explorer/github.js.map +1 -0
- package/cli/explorer/graphs.d.ts +7 -0
- package/cli/explorer/graphs.js +90 -95
- package/cli/explorer/graphs.js.map +1 -0
- package/cli/explorer/picker.d.ts +22 -0
- package/cli/explorer/picker.js +150 -0
- package/cli/explorer/picker.js.map +1 -0
- package/cli/explorer/report.d.ts +85 -0
- package/cli/explorer/report.js +60 -0
- package/cli/explorer/report.js.map +1 -0
- package/cli/explorer/session.d.ts +449 -0
- package/cli/explorer/session.js +143 -144
- package/cli/explorer/session.js.map +1 -0
- package/cli/explorer/views.d.ts +19 -0
- package/cli/explorer/views.js +465 -482
- package/cli/explorer/views.js.map +1 -0
- package/cli/explorer/wrap.d.ts +1 -0
- package/cli/explorer/wrap.js +28 -44
- package/cli/explorer/wrap.js.map +1 -0
- package/cli/main.d.ts +1 -0
- package/cli/main.js +214 -161
- package/cli/main.js.map +1 -0
- package/cli/prompt.d.ts +5 -0
- package/cli/prompt.js +84 -80
- package/cli/prompt.js.map +1 -0
- package/cli/scanOptions.d.ts +2 -0
- package/cli/scanOptions.js +11 -0
- package/cli/scanOptions.js.map +1 -0
- package/cli/ui.d.ts +33 -0
- package/cli/ui.js +35 -44
- package/cli/ui.js.map +1 -0
- package/cli/wizard.d.ts +187 -0
- package/cli/wizard.js +304 -284
- package/cli/wizard.js.map +1 -0
- package/package.json +15 -4
- package/public/app.d.ts +1 -0
- package/public/app.js +1057 -1009
- package/public/app.js.map +1 -0
- package/public/browser.d.ts +68 -0
- package/public/browser.js +2 -0
- package/public/browser.js.map +1 -0
- package/public/index.html +30 -13
- package/public/js/about.d.ts +6 -0
- package/public/js/about.js +152 -172
- package/public/js/about.js.map +1 -0
- package/public/js/aiDraft.d.ts +3 -0
- package/public/js/aiDraft.js +116 -124
- package/public/js/aiDraft.js.map +1 -0
- package/public/js/analysisPanel.d.ts +7 -0
- package/public/js/analysisPanel.js +166 -166
- package/public/js/analysisPanel.js.map +1 -0
- package/public/js/analysisReport.d.ts +38 -0
- package/public/js/analysisReport.js +105 -110
- package/public/js/analysisReport.js.map +1 -0
- package/public/js/api.d.ts +26 -0
- package/public/js/api.js +176 -167
- package/public/js/api.js.map +1 -0
- package/public/js/atlas.d.ts +6 -0
- package/public/js/atlas.js +50 -58
- package/public/js/atlas.js.map +1 -0
- package/public/js/blameView.d.ts +2 -0
- package/public/js/blameView.js +36 -37
- package/public/js/blameView.js.map +1 -0
- package/public/js/codeTab.d.ts +3 -0
- package/public/js/codeTab.js +175 -180
- package/public/js/codeTab.js.map +1 -0
- package/public/js/codeViewer.d.ts +5 -0
- package/public/js/codeViewer.js +162 -150
- package/public/js/codeViewer.js.map +1 -0
- package/public/js/components/FileChip.d.ts +9 -0
- package/public/js/components/FileChip.js +45 -49
- package/public/js/components/FileChip.js.map +1 -0
- package/public/js/components/MetricSparkline.d.ts +7 -0
- package/public/js/components/MetricSparkline.js +35 -44
- package/public/js/components/MetricSparkline.js.map +1 -0
- package/public/js/components/RiskBadge.d.ts +9 -0
- package/public/js/components/RiskBadge.js +55 -63
- package/public/js/components/RiskBadge.js.map +1 -0
- package/public/js/deepAnalysisView.d.ts +99 -0
- package/public/js/deepAnalysisView.js +282 -302
- package/public/js/deepAnalysisView.js.map +1 -0
- package/public/js/diagramPane.d.ts +8 -0
- package/public/js/diagramPane.js +133 -135
- package/public/js/diagramPane.js.map +1 -0
- package/public/js/diffView.d.ts +6 -0
- package/public/js/diffView.js +222 -209
- package/public/js/diffView.js.map +1 -0
- package/public/js/docsView.d.ts +2 -0
- package/public/js/docsView.js +441 -442
- package/public/js/docsView.js.map +1 -0
- package/public/js/dom.d.ts +189 -0
- package/public/js/dom.js +5 -0
- package/public/js/dom.js.map +1 -0
- package/public/js/fileSourceBrowser.d.ts +5 -0
- package/public/js/fileSourceBrowser.js +33 -41
- package/public/js/fileSourceBrowser.js.map +1 -0
- package/public/js/flameGraph.d.ts +5 -0
- package/public/js/flameGraph.js +62 -72
- package/public/js/flameGraph.js.map +1 -0
- package/public/js/forceGraph.d.ts +10 -0
- package/public/js/forceGraph.js +581 -556
- package/public/js/forceGraph.js.map +1 -0
- package/public/js/heatmap.d.ts +4 -0
- package/public/js/heatmap.js +142 -164
- package/public/js/heatmap.js.map +1 -0
- package/public/js/highlight.d.ts +2 -0
- package/public/js/highlight.js +116 -107
- package/public/js/highlight.js.map +1 -0
- package/public/js/html.d.ts +2 -0
- package/public/js/html.js +14 -44
- package/public/js/html.js.map +1 -0
- package/public/js/insightsView.d.ts +5 -0
- package/public/js/insightsView.js +93 -111
- package/public/js/insightsView.js.map +1 -0
- package/public/js/inspector.d.ts +37 -0
- package/public/js/inspector.js +416 -445
- package/public/js/inspector.js.map +1 -0
- package/public/js/llm.d.ts +113 -0
- package/public/js/llm.js +233 -272
- package/public/js/llm.js.map +1 -0
- package/public/js/mapView.d.ts +3 -0
- package/public/js/mapView.js +121 -120
- package/public/js/mapView.js.map +1 -0
- package/public/js/markdown.d.ts +3 -0
- package/public/js/markdown.js +84 -91
- package/public/js/markdown.js.map +1 -0
- package/public/js/mindmap.d.ts +32 -0
- package/public/js/mindmap.js +244 -259
- package/public/js/mindmap.js.map +1 -0
- package/public/js/mobilePanels.d.ts +5 -0
- package/public/js/mobilePanels.js +50 -0
- package/public/js/mobilePanels.js.map +1 -0
- package/public/js/repoFiles.d.ts +12 -0
- package/public/js/repoFiles.js +28 -27
- package/public/js/repoFiles.js.map +1 -0
- package/public/js/reviewView.d.ts +28 -0
- package/public/js/reviewView.js +256 -0
- package/public/js/reviewView.js.map +1 -0
- package/public/js/sbomView.d.ts +3 -0
- package/public/js/sbomView.js +59 -67
- package/public/js/sbomView.js.map +1 -0
- package/public/js/scanCache.d.ts +16 -0
- package/public/js/scanCache.js +67 -65
- package/public/js/scanCache.js.map +1 -0
- package/public/js/search.d.ts +7 -0
- package/public/js/search.js +868 -800
- package/public/js/search.js.map +1 -0
- package/public/js/searchLocal.d.ts +42 -0
- package/public/js/searchLocal.js +87 -0
- package/public/js/searchLocal.js.map +1 -0
- package/public/js/serverSettings.d.ts +5 -0
- package/public/js/serverSettings.js +153 -164
- package/public/js/serverSettings.js.map +1 -0
- package/public/js/state.d.ts +798 -0
- package/public/js/state.js +114 -122
- package/public/js/state.js.map +1 -0
- package/public/js/tour.d.ts +6 -0
- package/public/js/tour.js +5 -7
- package/public/js/tour.js.map +1 -0
- package/public/js/transitions.d.ts +2 -0
- package/public/js/transitions.js +9 -10
- package/public/js/transitions.js.map +1 -0
- package/public/js/tree.d.ts +12 -0
- package/public/js/tree.js +157 -154
- package/public/js/tree.js.map +1 -0
- package/public/js/workflowsView.d.ts +3 -0
- package/public/js/workflowsView.js +15 -22
- package/public/js/workflowsView.js.map +1 -0
- package/public/search.css +495 -0
- package/public/styles.css +163 -346
- package/public/workbench.css +166 -0
- package/server/apiAuth.d.ts +3 -0
- package/server/apiAuth.js +18 -20
- package/server/apiAuth.js.map +1 -0
- package/server/apiDiff.d.ts +2 -0
- package/server/apiDiff.js +20 -18
- package/server/apiDiff.js.map +1 -0
- package/server/apiDocs.d.ts +2 -0
- package/server/apiDocs.js +38 -40
- package/server/apiDocs.js.map +1 -0
- package/server/apiFile.d.ts +1 -0
- package/server/apiFile.js +14 -17
- package/server/apiFile.js.map +1 -0
- package/server/apiGitBlame.d.ts +2 -0
- package/server/apiGitBlame.js +50 -51
- package/server/apiGitBlame.js.map +1 -0
- package/server/apiMcp.d.ts +4 -0
- package/server/apiMcp.js +64 -66
- package/server/apiMcp.js.map +1 -0
- package/server/apiReview.d.ts +2 -0
- package/server/apiReview.js +45 -0
- package/server/apiReview.js.map +1 -0
- package/server/apiScan.d.ts +5 -0
- package/server/apiScan.js +90 -71
- package/server/apiScan.js.map +1 -0
- package/server/apiSearch.d.ts +33 -0
- package/server/apiSearch.js +184 -200
- package/server/apiSearch.js.map +1 -0
- package/server/apiSettings.d.ts +4 -0
- package/server/apiSettings.js +84 -85
- package/server/apiSettings.js.map +1 -0
- package/server/apiTools.d.ts +3 -0
- package/server/apiTools.js +55 -56
- package/server/apiTools.js.map +1 -0
- package/server/auth.d.ts +5 -0
- package/server/auth.js +54 -51
- package/server/auth.js.map +1 -0
- package/server/config.d.ts +42 -0
- package/server/config.js +189 -194
- package/server/config.js.map +1 -0
- package/server/daemon.d.ts +12 -0
- package/server/daemon.js +124 -114
- package/server/daemon.js.map +1 -0
- package/server/fileSourceNode.d.ts +2 -0
- package/server/fileSourceNode.js +34 -36
- package/server/fileSourceNode.js.map +1 -0
- package/server/gitClone.d.ts +9 -0
- package/server/gitClone.js +59 -61
- package/server/gitClone.js.map +1 -0
- package/server/gitDiff.d.ts +36 -0
- package/server/gitDiff.js +271 -169
- package/server/gitDiff.js.map +1 -0
- package/server/gitHistory.d.ts +12 -0
- package/server/gitHistory.js +80 -80
- package/server/gitHistory.js.map +1 -0
- package/server/gitRemote.d.ts +12 -0
- package/server/gitRemote.js +37 -38
- package/server/gitRemote.js.map +1 -0
- package/server/htmlText.d.ts +4 -0
- package/server/htmlText.js +16 -23
- package/server/htmlText.js.map +1 -0
- package/server/http.d.ts +5 -0
- package/server/http.js +27 -30
- package/server/http.js.map +1 -0
- package/server/httpGuards.d.ts +2 -0
- package/server/httpGuards.js +47 -43
- package/server/httpGuards.js.map +1 -0
- package/server/https.d.ts +34 -0
- package/server/https.js +121 -111
- package/server/https.js.map +1 -0
- package/server/index.d.ts +40 -0
- package/server/index.js +139 -147
- package/server/index.js.map +1 -0
- package/server/layout.d.ts +26 -0
- package/server/layout.js +59 -64
- package/server/layout.js.map +1 -0
- package/server/llmProxy.d.ts +3 -0
- package/server/llmProxy.js +137 -135
- package/server/llmProxy.js.map +1 -0
- package/server/logger.d.ts +38 -0
- package/server/logger.js +198 -211
- package/server/logger.js.map +1 -0
- package/server/mcp/analysis.d.ts +29 -0
- package/server/mcp/analysis.js +99 -120
- package/server/mcp/analysis.js.map +1 -0
- package/server/mcp/http.d.ts +9 -0
- package/server/mcp/http.js +128 -137
- package/server/mcp/http.js.map +1 -0
- package/server/mcp/runner.d.ts +68 -0
- package/server/mcp/runner.js +208 -218
- package/server/mcp/runner.js.map +1 -0
- package/server/mcp/server.d.ts +29 -0
- package/server/mcp/server.js +166 -179
- package/server/mcp/server.js.map +1 -0
- package/server/mcp/standalone.d.ts +1 -0
- package/server/mcp/standalone.js +8 -10
- package/server/mcp/standalone.js.map +1 -0
- package/server/mcp/tools.d.ts +2020 -0
- package/server/mcp/tools.js +523 -574
- package/server/mcp/tools.js.map +1 -0
- package/server/paths.d.ts +3 -0
- package/server/paths.js +17 -15
- package/server/paths.js.map +1 -0
- package/server/pidfile.d.ts +9 -0
- package/server/pidfile.js +43 -45
- package/server/pidfile.js.map +1 -0
- package/server/review.d.ts +5 -0
- package/server/review.js +35 -0
- package/server/review.js.map +1 -0
- package/server/router.d.ts +33 -0
- package/server/router.js +191 -197
- package/server/router.js.map +1 -0
- package/server/scanRequest.d.ts +3 -0
- package/server/scanRequest.js +36 -0
- package/server/scanRequest.js.map +1 -0
- package/server/searchIndex.d.ts +17 -0
- package/server/searchIndex.js +83 -80
- package/server/searchIndex.js.map +1 -0
- package/server/sessions.d.ts +14 -0
- package/server/sessions.js +62 -70
- package/server/sessions.js.map +1 -0
- package/server/startup.d.ts +118 -0
- package/server/startup.js +143 -148
- package/server/startup.js.map +1 -0
- package/server/static.d.ts +6 -0
- package/server/static.js +28 -31
- package/server/static.js.map +1 -0
- package/server/tools/install.d.ts +4 -0
- package/server/tools/install.js +176 -185
- package/server/tools/install.js.map +1 -0
- package/server/tools/parse.d.ts +8 -0
- package/server/tools/parse.js +112 -114
- package/server/tools/parse.js.map +1 -0
- package/server/tools/platform.d.ts +9 -0
- package/server/tools/platform.js +49 -47
- package/server/tools/platform.js.map +1 -0
- package/server/tools/registry.d.ts +137 -0
- package/server/tools/registry.js +173 -172
- package/server/tools/registry.js.map +1 -0
- package/server/tools/scan.d.ts +34 -0
- package/server/tools/scan.js +89 -98
- package/server/tools/scan.js.map +1 -0
- package/server/tools.d.ts +34 -0
- package/server/tools.js +94 -107
- package/server/tools.js.map +1 -0
- package/server/tunnel.d.ts +29 -0
- package/server/tunnel.js +61 -66
- package/server/tunnel.js.map +1 -0
- package/shared/analyzer/docs.d.ts +16 -0
- package/shared/analyzer/docs.js +99 -93
- package/shared/analyzer/docs.js.map +1 -0
- package/shared/analyzer/explainLocal.d.ts +4 -0
- package/shared/analyzer/explainLocal.js +122 -142
- package/shared/analyzer/explainLocal.js.map +1 -0
- package/shared/analyzer/github.d.ts +37 -0
- package/shared/analyzer/github.js +41 -43
- package/shared/analyzer/github.js.map +1 -0
- package/shared/analyzer/graph.d.ts +41 -0
- package/shared/analyzer/graph.js +393 -400
- package/shared/analyzer/graph.js.map +1 -0
- package/shared/analyzer/health.d.ts +33 -0
- package/shared/analyzer/health.js +197 -193
- package/shared/analyzer/health.js.map +1 -0
- package/shared/analyzer/history.d.ts +29 -0
- package/shared/analyzer/history.js +110 -111
- package/shared/analyzer/history.js.map +1 -0
- package/shared/analyzer/jsonConfig.d.ts +2 -0
- package/shared/analyzer/jsonConfig.js +61 -0
- package/shared/analyzer/jsonConfig.js.map +1 -0
- package/shared/analyzer/languages/csharp.d.ts +26 -0
- package/shared/analyzer/languages/csharp.js +83 -88
- package/shared/analyzer/languages/csharp.js.map +1 -0
- package/shared/analyzer/languages/generic.d.ts +23 -0
- package/shared/analyzer/languages/generic.js +94 -105
- package/shared/analyzer/languages/generic.js.map +1 -0
- package/shared/analyzer/languages/go.d.ts +24 -0
- package/shared/analyzer/languages/go.js +45 -54
- package/shared/analyzer/languages/go.js.map +1 -0
- package/shared/analyzer/languages/index.d.ts +6 -0
- package/shared/analyzer/languages/index.js +19 -20
- package/shared/analyzer/languages/index.js.map +1 -0
- package/shared/analyzer/languages/java.d.ts +20 -0
- package/shared/analyzer/languages/java.js +73 -78
- package/shared/analyzer/languages/java.js.map +1 -0
- package/shared/analyzer/languages/javascript.d.ts +12 -0
- package/shared/analyzer/languages/javascript.js +258 -209
- package/shared/analyzer/languages/javascript.js.map +1 -0
- package/shared/analyzer/languages/python.d.ts +23 -0
- package/shared/analyzer/languages/python.js +92 -100
- package/shared/analyzer/languages/python.js.map +1 -0
- package/shared/analyzer/languages/rust.d.ts +17 -0
- package/shared/analyzer/languages/rust.js +96 -98
- package/shared/analyzer/languages/rust.js.map +1 -0
- package/shared/analyzer/languages/typescript.d.ts +11 -0
- package/shared/analyzer/languages/typescript.js +117 -116
- package/shared/analyzer/languages/typescript.js.map +1 -0
- package/shared/analyzer/licenses.d.ts +18 -0
- package/shared/analyzer/licenses.js +130 -133
- package/shared/analyzer/licenses.js.map +1 -0
- package/shared/analyzer/metrics.d.ts +20 -0
- package/shared/analyzer/metrics.js +112 -104
- package/shared/analyzer/metrics.js.map +1 -0
- package/shared/analyzer/pathUtil.d.ts +10 -0
- package/shared/analyzer/pathUtil.js +29 -35
- package/shared/analyzer/pathUtil.js.map +1 -0
- package/shared/analyzer/patterns.d.ts +11 -0
- package/shared/analyzer/patterns.js +231 -253
- package/shared/analyzer/patterns.js.map +1 -0
- package/shared/analyzer/scan.d.ts +62 -0
- package/shared/analyzer/scan.js +451 -442
- package/shared/analyzer/scan.js.map +1 -0
- package/shared/analyzer/scanControl.d.ts +11 -0
- package/shared/analyzer/scanControl.js +62 -0
- package/shared/analyzer/scanControl.js.map +1 -0
- package/shared/analyzer/security.d.ts +18 -0
- package/shared/analyzer/security.js +159 -159
- package/shared/analyzer/security.js.map +1 -0
- package/shared/analyzer/services.d.ts +5 -0
- package/shared/analyzer/services.js +141 -138
- package/shared/analyzer/services.js.map +1 -0
- package/shared/analyzer/stack.d.ts +6 -0
- package/shared/analyzer/stack.js +134 -141
- package/shared/analyzer/stack.js.map +1 -0
- package/shared/analyzer/tour.d.ts +2 -0
- package/shared/analyzer/tour.js +45 -53
- package/shared/analyzer/tour.js.map +1 -0
- package/shared/analyzer/util.d.ts +8 -0
- package/shared/analyzer/util.js +130 -76
- package/shared/analyzer/util.js.map +1 -0
- package/shared/analyzer/workflows.d.ts +8 -0
- package/shared/analyzer/workflows.js +139 -134
- package/shared/analyzer/workflows.js.map +1 -0
- package/shared/contracts.d.ts +250 -0
- package/shared/contracts.js +2 -0
- package/shared/contracts.js.map +1 -0
- package/shared/diagram/aiFacts.d.ts +35 -0
- package/shared/diagram/aiFacts.js +102 -105
- package/shared/diagram/aiFacts.js.map +1 -0
- package/shared/diagram/aiMermaid.d.ts +5 -0
- package/shared/diagram/aiMermaid.js +46 -45
- package/shared/diagram/aiMermaid.js.map +1 -0
- package/shared/diagram/atlas.d.ts +16 -0
- package/shared/diagram/atlas.js +51 -60
- package/shared/diagram/atlas.js.map +1 -0
- package/shared/diagram/mermaid.d.ts +43 -0
- package/shared/diagram/mermaid.js +348 -370
- package/shared/diagram/mermaid.js.map +1 -0
- package/shared/review/contracts.d.ts +95 -0
- package/shared/review/contracts.js +2 -0
- package/shared/review/contracts.js.map +1 -0
- package/shared/review/review.d.ts +10 -0
- package/shared/review/review.js +184 -0
- package/shared/review/review.js.map +1 -0
- package/shared/search/query.d.ts +32 -0
- package/shared/search/query.js +395 -388
- package/shared/search/query.js.map +1 -0
package/public/js/tree.js
CHANGED
|
@@ -1,48 +1,47 @@
|
|
|
1
1
|
// Sidebar file tree. Built from the plain path list, rendered with
|
|
2
2
|
// collapsible folders, badges for entries and hubs, and a substring filter.
|
|
3
|
-
|
|
4
3
|
import { escapeHtml } from './html.js';
|
|
5
|
-
|
|
6
4
|
export function buildTree(allFiles) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
5
|
+
const root = { name: '', path: '', dirs: new Map(), files: [] };
|
|
6
|
+
for (const path of allFiles) {
|
|
7
|
+
const parts = path.split('/');
|
|
8
|
+
let node = root;
|
|
9
|
+
for (let i = 0; i < parts.length - 1; i++) {
|
|
10
|
+
const name = parts[i];
|
|
11
|
+
if (!node.dirs.has(name)) {
|
|
12
|
+
const dirPath = parts.slice(0, i + 1).join('/');
|
|
13
|
+
node.dirs.set(name, { name, path: dirPath, dirs: new Map(), files: [] });
|
|
14
|
+
}
|
|
15
|
+
node = node.dirs.get(name);
|
|
16
|
+
}
|
|
17
|
+
node.files.push(path);
|
|
18
18
|
}
|
|
19
|
-
|
|
20
|
-
}
|
|
21
|
-
return root;
|
|
19
|
+
return root;
|
|
22
20
|
}
|
|
23
|
-
|
|
24
21
|
// The folder node at `path`, or null if no such folder exists. `''` is the root,
|
|
25
22
|
// which is a real folder here and not "no folder" — several callers pass the
|
|
26
23
|
// empty string on purpose.
|
|
27
24
|
export function findNode(root, path) {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
25
|
+
if (!path)
|
|
26
|
+
return root;
|
|
27
|
+
let node = root;
|
|
28
|
+
for (const part of path.split('/')) {
|
|
29
|
+
node = node.dirs?.get(part);
|
|
30
|
+
if (!node)
|
|
31
|
+
return null;
|
|
32
|
+
}
|
|
33
|
+
return node;
|
|
35
34
|
}
|
|
36
|
-
|
|
37
35
|
// Files at or below a node. Used to rank folders by size when choosing which
|
|
38
36
|
// ones are worth documenting.
|
|
39
37
|
export function countFiles(node) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
38
|
+
if (!node)
|
|
39
|
+
return 0;
|
|
40
|
+
let n = node.files.length;
|
|
41
|
+
for (const dir of node.dirs.values())
|
|
42
|
+
n += countFiles(dir);
|
|
43
|
+
return n;
|
|
44
44
|
}
|
|
45
|
-
|
|
46
45
|
// A copy of the tree with the filtered-out files removed, and with folders that
|
|
47
46
|
// end up holding nothing removed too — otherwise the tree map fills with empty
|
|
48
47
|
// scaffolding whose labels no longer match anything inside them.
|
|
@@ -56,145 +55,149 @@ export function countFiles(node) {
|
|
|
56
55
|
// The predicates are passed in rather than built here: this file has to stay
|
|
57
56
|
// importable in Node to be testable, which rules out reaching into `/shared/`.
|
|
58
57
|
export function pruneTree(root, include, matchesFolder = null) {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
58
|
+
if (!include)
|
|
59
|
+
return root;
|
|
60
|
+
const walk = (node) => {
|
|
61
|
+
if (node.path && matchesFolder?.(node.path))
|
|
62
|
+
return node;
|
|
63
|
+
const dirs = new Map();
|
|
64
|
+
for (const [name, child] of node.dirs) {
|
|
65
|
+
const pruned = walk(child);
|
|
66
|
+
if (pruned)
|
|
67
|
+
dirs.set(name, pruned);
|
|
68
|
+
}
|
|
69
|
+
const files = node.files.filter(include);
|
|
70
|
+
if (!node.path)
|
|
71
|
+
return { ...node, dirs, files }; // the root always survives
|
|
72
|
+
if (!dirs.size && !files.length)
|
|
73
|
+
return null;
|
|
74
|
+
return { ...node, dirs, files };
|
|
75
|
+
};
|
|
76
|
+
return walk(root);
|
|
73
77
|
}
|
|
74
|
-
|
|
75
78
|
// The set of folder ids to treat as open when the reader picks a depth from the
|
|
76
79
|
// stage's depth selector. Ids are `dir:` + path, which is the vocabulary the tree
|
|
77
80
|
// map's cells use; `dir:` alone is the root.
|
|
78
81
|
export function expandedToDepth(root, maxDepth) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
82
|
+
const out = new Set();
|
|
83
|
+
const walk = (node, depth) => {
|
|
84
|
+
if (depth > maxDepth)
|
|
85
|
+
return;
|
|
86
|
+
out.add('dir:' + node.path);
|
|
87
|
+
for (const d of node.dirs.values())
|
|
88
|
+
walk(d, depth + 1);
|
|
89
|
+
};
|
|
90
|
+
walk(root, 0);
|
|
91
|
+
return out;
|
|
87
92
|
}
|
|
88
|
-
|
|
89
93
|
const openState = new Set();
|
|
90
|
-
|
|
91
94
|
export function resetOpenState() {
|
|
92
|
-
|
|
95
|
+
openState.clear();
|
|
93
96
|
}
|
|
94
|
-
|
|
95
97
|
export function renderTree(container, tree, ctx) {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
98
|
+
const { facts, filter = '', selected, onFile, onFolder } = ctx;
|
|
99
|
+
container.innerHTML = '';
|
|
100
|
+
const parsedSet = new Set(ctx.parsedPaths || []);
|
|
101
|
+
const hubSet = new Set((facts?.hubs || []).filter((h) => h.fanIn >= 4).map((h) => h.path));
|
|
102
|
+
const entrySet = new Set(facts?.entries || []);
|
|
103
|
+
const needle = filter.trim().toLowerCase();
|
|
104
|
+
const frag = document.createDocumentFragment();
|
|
105
|
+
const renderDir = (node, parent) => {
|
|
106
|
+
const dirNames = [...node.dirs.keys()].sort();
|
|
107
|
+
const filePaths = node.files.slice().sort();
|
|
108
|
+
for (const name of dirNames) {
|
|
109
|
+
const child = node.dirs.get(name);
|
|
110
|
+
if (needle && !subtreeHas(child, needle))
|
|
111
|
+
continue;
|
|
112
|
+
const wrap = document.createElement('div');
|
|
113
|
+
wrap.className = 'tree-dir' + (openState.has(child.path) || needle ? ' is-open' : '');
|
|
114
|
+
const head = document.createElement('div');
|
|
115
|
+
head.className = 'tree-dir-head';
|
|
116
|
+
const count = countFiles(child);
|
|
117
|
+
head.innerHTML = `<span class="tree-caret">▸</span><span>${escapeHtml(name)}/</span><span class="tree-count">${count}</span>`;
|
|
118
|
+
head.addEventListener('click', () => {
|
|
119
|
+
if (openState.has(child.path))
|
|
120
|
+
openState.delete(child.path);
|
|
121
|
+
else
|
|
122
|
+
openState.add(child.path);
|
|
123
|
+
wrap.classList.toggle('is-open');
|
|
124
|
+
onFolder?.(child.path);
|
|
125
|
+
});
|
|
126
|
+
wrap.appendChild(head);
|
|
127
|
+
const kids = document.createElement('div');
|
|
128
|
+
kids.className = 'tree-children';
|
|
129
|
+
renderDir(child, kids);
|
|
130
|
+
wrap.appendChild(kids);
|
|
131
|
+
parent.appendChild(wrap);
|
|
132
|
+
}
|
|
133
|
+
for (const path of filePaths) {
|
|
134
|
+
const name = path.split('/').pop();
|
|
135
|
+
if (needle && !path.toLowerCase().includes(needle))
|
|
136
|
+
continue;
|
|
137
|
+
const el = document.createElement('div');
|
|
138
|
+
el.className = 'tree-file' + (path === selected ? ' is-selected' : '');
|
|
139
|
+
el.dataset.path = path;
|
|
140
|
+
const dot = document.createElement('span');
|
|
141
|
+
dot.className = 'tree-dot';
|
|
142
|
+
dot.style.backgroundColor = getExtColor(path);
|
|
143
|
+
el.appendChild(dot);
|
|
144
|
+
const label = document.createElement('span');
|
|
145
|
+
label.textContent = name;
|
|
146
|
+
if (!parsedSet.has(path))
|
|
147
|
+
label.style.color = 'var(--faint)';
|
|
148
|
+
el.appendChild(label);
|
|
149
|
+
if (entrySet.has(path)) {
|
|
150
|
+
el.appendChild(badge('in', 'is-entry'));
|
|
151
|
+
}
|
|
152
|
+
else if (hubSet.has(path)) {
|
|
153
|
+
el.appendChild(badge('hub', 'is-hub'));
|
|
154
|
+
}
|
|
155
|
+
el.addEventListener('click', () => onFile?.(path));
|
|
156
|
+
parent.appendChild(el);
|
|
157
|
+
}
|
|
158
|
+
};
|
|
159
|
+
renderDir(tree, frag);
|
|
160
|
+
container.appendChild(frag);
|
|
161
|
+
if (!container.children.length) {
|
|
162
|
+
container.innerHTML = '<p style="padding:10px;color:var(--faint)">Nothing matches that filter.</p>';
|
|
159
163
|
}
|
|
160
|
-
};
|
|
161
|
-
|
|
162
|
-
renderDir(tree, frag);
|
|
163
|
-
container.appendChild(frag);
|
|
164
|
-
|
|
165
|
-
if (!container.children.length) {
|
|
166
|
-
container.innerHTML = '<p style="padding:10px;color:var(--faint)">Nothing matches that filter.</p>';
|
|
167
|
-
}
|
|
168
164
|
}
|
|
169
|
-
|
|
170
165
|
function subtreeHas(node, needle) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
166
|
+
if (node.path.toLowerCase().includes(needle))
|
|
167
|
+
return true;
|
|
168
|
+
for (const f of node.files)
|
|
169
|
+
if (f.toLowerCase().includes(needle))
|
|
170
|
+
return true;
|
|
171
|
+
for (const child of node.dirs.values())
|
|
172
|
+
if (subtreeHas(child, needle))
|
|
173
|
+
return true;
|
|
174
|
+
return false;
|
|
175
175
|
}
|
|
176
|
-
|
|
177
176
|
function badge(text, cls) {
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
177
|
+
const b = document.createElement('span');
|
|
178
|
+
b.className = 'tree-badge ' + cls;
|
|
179
|
+
b.textContent = text;
|
|
180
|
+
return b;
|
|
182
181
|
}
|
|
183
|
-
|
|
184
182
|
function getExtColor(path) {
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
183
|
+
const ext = (path.match(/\.([A-Za-z0-9]+)$/) || [, ''])[1].toLowerCase();
|
|
184
|
+
switch (ext) {
|
|
185
|
+
case 'ts':
|
|
186
|
+
case 'tsx': return '#3178c6';
|
|
187
|
+
case 'js':
|
|
188
|
+
case 'jsx':
|
|
189
|
+
case 'mjs':
|
|
190
|
+
case 'cjs': return '#f7df1e';
|
|
191
|
+
case 'py': return '#3572A5';
|
|
192
|
+
case 'rs': return '#dea584';
|
|
193
|
+
case 'go': return '#00ADD8';
|
|
194
|
+
case 'java': return '#b07219';
|
|
195
|
+
case 'cs': return '#178600';
|
|
196
|
+
case 'html': return '#e34c26';
|
|
197
|
+
case 'css': return '#563d7c';
|
|
198
|
+
case 'json': return '#cbcb41';
|
|
199
|
+
case 'md': return '#083fa1';
|
|
200
|
+
default: return 'var(--faint)';
|
|
201
|
+
}
|
|
200
202
|
}
|
|
203
|
+
//# sourceMappingURL=tree.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tree.js","sourceRoot":"","sources":["../../src/public/js/tree.ts"],"names":[],"mappings":"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","sourcesContent":["// Sidebar file tree. Built from the plain path list, rendered with\n// collapsible folders, badges for entries and hubs, and a substring filter.\n\nimport { escapeHtml } from './html.js';\n\nexport function buildTree(allFiles) {\n const root = { name: '', path: '', dirs: new Map(), files: [] };\n for (const path of allFiles) {\n const parts = path.split('/');\n let node = root;\n for (let i = 0; i < parts.length - 1; i++) {\n const name = parts[i];\n if (!node.dirs.has(name)) {\n const dirPath = parts.slice(0, i + 1).join('/');\n node.dirs.set(name, { name, path: dirPath, dirs: new Map(), files: [] });\n }\n node = node.dirs.get(name);\n }\n node.files.push(path);\n }\n return root;\n}\n\n// The folder node at `path`, or null if no such folder exists. `''` is the root,\n// which is a real folder here and not \"no folder\" — several callers pass the\n// empty string on purpose.\nexport function findNode(root, path) {\n if (!path) return root;\n let node = root;\n for (const part of path.split('/')) {\n node = node.dirs?.get(part);\n if (!node) return null;\n }\n return node;\n}\n\n// Files at or below a node. Used to rank folders by size when choosing which\n// ones are worth documenting.\nexport function countFiles(node) {\n if (!node) return 0;\n let n = node.files.length;\n for (const dir of node.dirs.values()) n += countFiles(dir);\n return n;\n}\n\n// A copy of the tree with the filtered-out files removed, and with folders that\n// end up holding nothing removed too — otherwise the tree map fills with empty\n// scaffolding whose labels no longer match anything inside them.\n//\n// `include` is a predicate over file paths, and `matchesFolder` an optional one\n// over folder paths: a folder whose own name matches keeps its whole branch,\n// because searching for \"lib\" should show you lib's contents rather than an empty\n// folder named lib. The root always survives, even when nothing matches, so the\n// caller has something to render instead of null.\n//\n// The predicates are passed in rather than built here: this file has to stay\n// importable in Node to be testable, which rules out reaching into `/shared/`.\nexport function pruneTree(root, include, matchesFolder = null) {\n if (!include) return root;\n const walk = (node) => {\n if (node.path && matchesFolder?.(node.path)) return node;\n const dirs = new Map();\n for (const [name, child] of node.dirs) {\n const pruned = walk(child);\n if (pruned) dirs.set(name, pruned);\n }\n const files = node.files.filter(include);\n if (!node.path) return { ...node, dirs, files }; // the root always survives\n if (!dirs.size && !files.length) return null;\n return { ...node, dirs, files };\n };\n return walk(root);\n}\n\n// The set of folder ids to treat as open when the reader picks a depth from the\n// stage's depth selector. Ids are `dir:` + path, which is the vocabulary the tree\n// map's cells use; `dir:` alone is the root.\nexport function expandedToDepth(root, maxDepth): Set<string> {\n const out = new Set<string>();\n const walk = (node, depth) => {\n if (depth > maxDepth) return;\n out.add('dir:' + node.path);\n for (const d of node.dirs.values()) walk(d, depth + 1);\n };\n walk(root, 0);\n return out;\n}\n\nconst openState = new Set();\n\nexport function resetOpenState() {\n openState.clear();\n}\n\nexport function renderTree(container, tree, ctx) {\n const { facts, filter = '', selected, onFile, onFolder } = ctx;\n container.innerHTML = '';\n const parsedSet = new Set(ctx.parsedPaths || []);\n const hubSet = new Set((facts?.hubs || []).filter((h) => h.fanIn >= 4).map((h) => h.path));\n const entrySet = new Set(facts?.entries || []);\n const needle = filter.trim().toLowerCase();\n\n const frag = document.createDocumentFragment();\n\n const renderDir = (node, parent) => {\n const dirNames = [...node.dirs.keys()].sort();\n const filePaths = node.files.slice().sort();\n\n for (const name of dirNames) {\n const child = node.dirs.get(name);\n if (needle && !subtreeHas(child, needle)) continue;\n\n const wrap = document.createElement('div');\n wrap.className = 'tree-dir' + (openState.has(child.path) || needle ? ' is-open' : '');\n\n const head = document.createElement('div');\n head.className = 'tree-dir-head';\n const count = countFiles(child);\n head.innerHTML = `<span class=\"tree-caret\">▸</span><span>${escapeHtml(name)}/</span><span class=\"tree-count\">${count}</span>`;\n head.addEventListener('click', () => {\n if (openState.has(child.path)) openState.delete(child.path);\n else openState.add(child.path);\n wrap.classList.toggle('is-open');\n onFolder?.(child.path);\n });\n wrap.appendChild(head);\n\n const kids = document.createElement('div');\n kids.className = 'tree-children';\n renderDir(child, kids);\n wrap.appendChild(kids);\n parent.appendChild(wrap);\n }\n\n for (const path of filePaths) {\n const name = path.split('/').pop();\n if (needle && !path.toLowerCase().includes(needle)) continue;\n const el = document.createElement('div');\n el.className = 'tree-file' + (path === selected ? ' is-selected' : '');\n el.dataset.path = path;\n\n const dot = document.createElement('span');\n dot.className = 'tree-dot';\n dot.style.backgroundColor = getExtColor(path);\n el.appendChild(dot);\n\n const label = document.createElement('span');\n label.textContent = name;\n if (!parsedSet.has(path)) label.style.color = 'var(--faint)';\n el.appendChild(label);\n\n if (entrySet.has(path)) {\n el.appendChild(badge('in', 'is-entry'));\n } else if (hubSet.has(path)) {\n el.appendChild(badge('hub', 'is-hub'));\n }\n el.addEventListener('click', () => onFile?.(path));\n parent.appendChild(el);\n }\n };\n\n renderDir(tree, frag);\n container.appendChild(frag);\n\n if (!container.children.length) {\n container.innerHTML = '<p style=\"padding:10px;color:var(--faint)\">Nothing matches that filter.</p>';\n }\n}\n\nfunction subtreeHas(node, needle) {\n if (node.path.toLowerCase().includes(needle)) return true;\n for (const f of node.files) if (f.toLowerCase().includes(needle)) return true;\n for (const child of node.dirs.values()) if (subtreeHas(child, needle)) return true;\n return false;\n}\n\nfunction badge(text, cls) {\n const b = document.createElement('span');\n b.className = 'tree-badge ' + cls;\n b.textContent = text;\n return b;\n}\n\nfunction getExtColor(path) {\n const ext = (path.match(/\\.([A-Za-z0-9]+)$/) || [, ''])[1].toLowerCase();\n switch (ext) {\n case 'ts': case 'tsx': return '#3178c6';\n case 'js': case 'jsx': case 'mjs': case 'cjs': return '#f7df1e';\n case 'py': return '#3572A5';\n case 'rs': return '#dea584';\n case 'go': return '#00ADD8';\n case 'java': return '#b07219';\n case 'cs': return '#178600';\n case 'html': return '#e34c26';\n case 'css': return '#563d7c';\n case 'json': return '#cbcb41';\n case 'md': return '#083fa1';\n default: return 'var(--faint)';\n }\n}\n"]}
|
|
@@ -1,25 +1,21 @@
|
|
|
1
1
|
// GitHub Actions & CI/CD Workflows View.
|
|
2
2
|
// Renders workflow triggers, job dependency DAGs, and execution steps.
|
|
3
|
-
|
|
4
3
|
import { escapeHtml } from './html.js';
|
|
5
|
-
|
|
6
4
|
export function renderWorkflows(container, { scan }) {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
container.innerHTML = `
|
|
5
|
+
if (!container)
|
|
6
|
+
return;
|
|
7
|
+
const workflows = scan?.workflows || [];
|
|
8
|
+
if (!workflows.length) {
|
|
9
|
+
container.innerHTML = `
|
|
13
10
|
<div class="workflows-empty-wrap">
|
|
14
11
|
<div class="wf-empty-icon">⚙️</div>
|
|
15
12
|
<h3>No CI/CD Workflows Detected</h3>
|
|
16
13
|
<p>No GitHub Actions workflows were found under <code>.github/workflows/</code> in this repository.</p>
|
|
17
14
|
</div>
|
|
18
15
|
`;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
container.innerHTML = `
|
|
16
|
+
return;
|
|
17
|
+
}
|
|
18
|
+
container.innerHTML = `
|
|
23
19
|
<div class="workflows-layout">
|
|
24
20
|
<header class="workflows-header">
|
|
25
21
|
<div>
|
|
@@ -35,12 +31,10 @@ export function renderWorkflows(container, { scan }) {
|
|
|
35
31
|
</div>
|
|
36
32
|
`;
|
|
37
33
|
}
|
|
38
|
-
|
|
39
34
|
function renderWorkflowCard(wf) {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
return `
|
|
35
|
+
const triggers = wf.triggers || [];
|
|
36
|
+
const jobs = wf.jobs || [];
|
|
37
|
+
return `
|
|
44
38
|
<article class="workflow-card">
|
|
45
39
|
<div class="wf-card-top">
|
|
46
40
|
<div class="wf-title-area">
|
|
@@ -62,12 +56,10 @@ function renderWorkflowCard(wf) {
|
|
|
62
56
|
</article>
|
|
63
57
|
`;
|
|
64
58
|
}
|
|
65
|
-
|
|
66
59
|
function renderJobCard(job) {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
return `
|
|
60
|
+
const steps = job.steps || [];
|
|
61
|
+
const needs = job.needs || [];
|
|
62
|
+
return `
|
|
71
63
|
<div class="wf-job-card">
|
|
72
64
|
<div class="wf-job-head">
|
|
73
65
|
<span class="wf-job-name">${escapeHtml(job.name)}</span>
|
|
@@ -93,3 +85,4 @@ function renderJobCard(job) {
|
|
|
93
85
|
</div>
|
|
94
86
|
`;
|
|
95
87
|
}
|
|
88
|
+
//# sourceMappingURL=workflowsView.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workflowsView.js","sourceRoot":"","sources":["../../src/public/js/workflowsView.ts"],"names":[],"mappings":"AAAA,yCAAyC;AACzC,uEAAuE;AAEvE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,MAAM,UAAU,eAAe,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE;IACjD,IAAI,CAAC,SAAS;QAAE,OAAO;IAEvB,MAAM,SAAS,GAAG,IAAI,EAAE,SAAS,IAAI,EAAE,CAAC;IAExC,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC;QACtB,SAAS,CAAC,SAAS,GAAG;;;;;;KAMrB,CAAC;QACF,OAAO;IACT,CAAC;IAED,SAAS,CAAC,SAAS,GAAG;;;;;;;sCAOc,SAAS,CAAC,MAAM,YAAY,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG;;;;UAIzF,SAAS,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,kBAAkB,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;GAG7D,CAAC;AACJ,CAAC;AAED,SAAS,kBAAkB,CAAC,EAAE;IAC5B,MAAM,QAAQ,GAAG,EAAE,CAAC,QAAQ,IAAI,EAAE,CAAC;IACnC,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,IAAI,EAAE,CAAC;IAE3B,OAAO;;;;kCAIyB,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC;uCACd,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC;;;;YAI9C,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iCAAiC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,mDAAmD;;;;;oDAKpG,IAAI,CAAC,MAAM;;YAEnD,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,2CAA2C;;;;GAIlG,CAAC;AACJ,CAAC;AAED,SAAS,aAAa,CAAC,GAAG;IACxB,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAC9B,MAAM,KAAK,GAAG,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;IAE9B,OAAO;;;oCAG2B,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC;kCACtB,UAAU,CAAC,GAAG,CAAC,MAAM,IAAI,eAAe,CAAC;;;QAGnE,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC;;;YAGX,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,6BAA6B,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;OAEnF,CAAC,CAAC,CAAC,EAAE;;;UAGF,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,EAAE,CAAC;;wCAEQ,GAAG,GAAG,CAAC;gDACC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;cAC3E,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,uCAAuC,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;;SAE1H,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC;;;GAGhB,CAAC;AACJ,CAAC","sourcesContent":["// GitHub Actions & CI/CD Workflows View.\n// Renders workflow triggers, job dependency DAGs, and execution steps.\n\nimport { escapeHtml } from './html.js';\n\nexport function renderWorkflows(container, { scan }) {\n if (!container) return;\n\n const workflows = scan?.workflows || [];\n\n if (!workflows.length) {\n container.innerHTML = `\n <div class=\"workflows-empty-wrap\">\n <div class=\"wf-empty-icon\">⚙️</div>\n <h3>No CI/CD Workflows Detected</h3>\n <p>No GitHub Actions workflows were found under <code>.github/workflows/</code> in this repository.</p>\n </div>\n `;\n return;\n }\n\n container.innerHTML = `\n <div class=\"workflows-layout\">\n <header class=\"workflows-header\">\n <div>\n <h2>CI/CD Workflows</h2>\n <span class=\"wf-sub\">Automated build, test, and release pipelines</span>\n </div>\n <div class=\"wf-count-badge\">${workflows.length} workflow${workflows.length === 1 ? '' : 's'}</div>\n </header>\n\n <div class=\"workflows-list\">\n ${workflows.map((wf) => renderWorkflowCard(wf)).join('')}\n </div>\n </div>\n `;\n}\n\nfunction renderWorkflowCard(wf) {\n const triggers = wf.triggers || [];\n const jobs = wf.jobs || [];\n\n return `\n <article class=\"workflow-card\">\n <div class=\"wf-card-top\">\n <div class=\"wf-title-area\">\n <span class=\"wf-name\">${escapeHtml(wf.name)}</span>\n <span class=\"wf-file-path\">${escapeHtml(wf.file)}</span>\n </div>\n <div class=\"wf-triggers\">\n <span class=\"wf-trigger-label\">Triggers:</span>\n ${triggers.map((t) => `<span class=\"wf-trigger-chip\">${escapeHtml(t)}</span>`).join('') || '<span class=\"wf-trigger-chip is-none\">none</span>'}\n </div>\n </div>\n\n <div class=\"wf-jobs-pipeline\">\n <div class=\"wf-jobs-title\">Pipeline Jobs (${jobs.length})</div>\n <div class=\"wf-jobs-grid\">\n ${jobs.map((j) => renderJobCard(j)).join('') || '<p class=\"wf-no-jobs\">No jobs defined</p>'}\n </div>\n </div>\n </article>\n `;\n}\n\nfunction renderJobCard(job) {\n const steps = job.steps || [];\n const needs = job.needs || [];\n\n return `\n <div class=\"wf-job-card\">\n <div class=\"wf-job-head\">\n <span class=\"wf-job-name\">${escapeHtml(job.name)}</span>\n <span class=\"wf-job-os\">${escapeHtml(job.runsOn || 'ubuntu-latest')}</span>\n </div>\n\n ${needs.length ? `\n <div class=\"wf-job-needs\">\n <span>Depends on:</span>\n ${needs.map((n) => `<span class=\"wf-need-tag\">${escapeHtml(n)}</span>`).join('')}\n </div>\n ` : ''}\n\n <div class=\"wf-steps-list\">\n ${steps.map((s, idx) => `\n <div class=\"wf-step-item\">\n <span class=\"wf-step-num\">${idx + 1}</span>\n <span class=\"wf-step-name\" title=\"${escapeHtml(s.name)}\">${escapeHtml(s.name)}</span>\n ${s.uses ? `<span class=\"wf-step-action\" title=\"${escapeHtml(s.uses)}\">${escapeHtml(s.uses.split('@')[0])}</span>` : ''}\n </div>\n `).join('')}\n </div>\n </div>\n `;\n}\n"]}
|