@opensip-cli/dashboard 0.1.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/LICENSE +202 -0
- package/NOTICE +8 -0
- package/README.md +31 -0
- package/dist/__tests__/catalog-provenance.test.d.ts +11 -0
- package/dist/__tests__/catalog-provenance.test.d.ts.map +1 -0
- package/dist/__tests__/catalog-provenance.test.js +130 -0
- package/dist/__tests__/catalog-provenance.test.js.map +1 -0
- package/dist/__tests__/coupling-attribution.test.d.ts +9 -0
- package/dist/__tests__/coupling-attribution.test.d.ts.map +1 -0
- package/dist/__tests__/coupling-attribution.test.js +99 -0
- package/dist/__tests__/coupling-attribution.test.js.map +1 -0
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts +16 -0
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-bundle-weight.test.js +73 -0
- package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -0
- package/dist/__tests__/dashboard-cell-containment.test.d.ts +2 -0
- package/dist/__tests__/dashboard-cell-containment.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-cell-containment.test.js +49 -0
- package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts +10 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.js +40 -0
- package/dist/__tests__/dashboard-cytoscape-vendor.test.js.map +1 -0
- package/dist/__tests__/dashboard-editor-link.test.d.ts +5 -0
- package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-editor-link.test.js +36 -0
- package/dist/__tests__/dashboard-editor-link.test.js.map +1 -0
- package/dist/__tests__/dashboard-filters.test.d.ts +9 -0
- package/dist/__tests__/dashboard-filters.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-filters.test.js +95 -0
- package/dist/__tests__/dashboard-filters.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.d.ts +9 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.js +87 -0
- package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-card.test.d.ts +10 -0
- package/dist/__tests__/dashboard-function-card.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-card.test.js +403 -0
- package/dist/__tests__/dashboard-function-card.test.js.map +1 -0
- package/dist/__tests__/dashboard-function-row.test.d.ts +11 -0
- package/dist/__tests__/dashboard-function-row.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-function-row.test.js +101 -0
- package/dist/__tests__/dashboard-function-row.test.js.map +1 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts +9 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js +75 -0
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts +13 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.js +55 -0
- package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-scc.test.d.ts +17 -0
- package/dist/__tests__/dashboard-graph-scc.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-scc.test.js +89 -0
- package/dist/__tests__/dashboard-graph-scc.test.js.map +1 -0
- package/dist/__tests__/dashboard-graph-view-model.test.d.ts +12 -0
- package/dist/__tests__/dashboard-graph-view-model.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-graph-view-model.test.js +331 -0
- package/dist/__tests__/dashboard-graph-view-model.test.js.map +1 -0
- package/dist/__tests__/dashboard-help-drawer.test.d.ts +9 -0
- package/dist/__tests__/dashboard-help-drawer.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-help-drawer.test.js +101 -0
- package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -0
- package/dist/__tests__/dashboard-html.test.d.ts +2 -0
- package/dist/__tests__/dashboard-html.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-html.test.js +169 -0
- package/dist/__tests__/dashboard-html.test.js.map +1 -0
- package/dist/__tests__/dashboard-indexes.test.d.ts +9 -0
- package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-indexes.test.js +211 -0
- package/dist/__tests__/dashboard-indexes.test.js.map +1 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts +6 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-path-utils.test.js +54 -0
- package/dist/__tests__/dashboard-path-utils.test.js.map +1 -0
- package/dist/__tests__/dashboard-search.test.d.ts +5 -0
- package/dist/__tests__/dashboard-search.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-search.test.js +46 -0
- package/dist/__tests__/dashboard-search.test.js.map +1 -0
- package/dist/__tests__/dashboard-sessions.test.d.ts +14 -0
- package/dist/__tests__/dashboard-sessions.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-sessions.test.js +330 -0
- package/dist/__tests__/dashboard-sessions.test.js.map +1 -0
- package/dist/__tests__/dashboard-trace.test.d.ts +5 -0
- package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-trace.test.js +147 -0
- package/dist/__tests__/dashboard-trace.test.js.map +1 -0
- package/dist/__tests__/dashboard-validation.integration.test.d.ts +14 -0
- package/dist/__tests__/dashboard-validation.integration.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-validation.integration.test.js +221 -0
- package/dist/__tests__/dashboard-validation.integration.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-conformance.test.d.ts +12 -0
- package/dist/__tests__/dashboard-view-conformance.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-conformance.test.js +58 -0
- package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-coupling.test.d.ts +7 -0
- package/dist/__tests__/dashboard-view-coupling.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-coupling.test.js +381 -0
- package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-distribution.test.d.ts +10 -0
- package/dist/__tests__/dashboard-view-distribution.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-distribution.test.js +272 -0
- package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-graph.test.d.ts +13 -0
- package/dist/__tests__/dashboard-view-graph.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-graph.test.js +332 -0
- package/dist/__tests__/dashboard-view-graph.test.js.map +1 -0
- package/dist/__tests__/dashboard-view-template.test.d.ts +21 -0
- package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-view-template.test.js +153 -0
- package/dist/__tests__/dashboard-view-template.test.js.map +1 -0
- package/dist/__tests__/dashboard.test.d.ts +2 -0
- package/dist/__tests__/dashboard.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard.test.js +129 -0
- package/dist/__tests__/dashboard.test.js.map +1 -0
- package/dist/__tests__/graph-tab.test.d.ts +10 -0
- package/dist/__tests__/graph-tab.test.d.ts.map +1 -0
- package/dist/__tests__/graph-tab.test.js +76 -0
- package/dist/__tests__/graph-tab.test.js.map +1 -0
- package/dist/checks.d.ts +7 -0
- package/dist/checks.d.ts.map +1 -0
- package/dist/checks.js +283 -0
- package/dist/checks.js.map +1 -0
- package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -0
- package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -0
- package/dist/code-paths/__tests__/views-registry.test.js +39 -0
- package/dist/code-paths/__tests__/views-registry.test.js.map +1 -0
- package/dist/code-paths/catalog-provenance.d.ts +22 -0
- package/dist/code-paths/catalog-provenance.d.ts.map +1 -0
- package/dist/code-paths/catalog-provenance.js +108 -0
- package/dist/code-paths/catalog-provenance.js.map +1 -0
- package/dist/code-paths/catalog-recipes-tables.d.ts +11 -0
- package/dist/code-paths/catalog-recipes-tables.d.ts.map +1 -0
- package/dist/code-paths/catalog-recipes-tables.js +86 -0
- package/dist/code-paths/catalog-recipes-tables.js.map +1 -0
- package/dist/code-paths/cytoscape-vendor.d.ts +27 -0
- package/dist/code-paths/cytoscape-vendor.d.ts.map +1 -0
- package/dist/code-paths/cytoscape-vendor.js +68 -0
- package/dist/code-paths/cytoscape-vendor.js.map +1 -0
- package/dist/code-paths/editor-link.d.ts +10 -0
- package/dist/code-paths/editor-link.d.ts.map +1 -0
- package/dist/code-paths/editor-link.js +20 -0
- package/dist/code-paths/editor-link.js.map +1 -0
- package/dist/code-paths/filters.d.ts +19 -0
- package/dist/code-paths/filters.d.ts.map +1 -0
- package/dist/code-paths/filters.js +47 -0
- package/dist/code-paths/filters.js.map +1 -0
- package/dist/code-paths/function-card.d.ts +15 -0
- package/dist/code-paths/function-card.d.ts.map +1 -0
- package/dist/code-paths/function-card.js +169 -0
- package/dist/code-paths/function-card.js.map +1 -0
- package/dist/code-paths/function-row.d.ts +17 -0
- package/dist/code-paths/function-row.d.ts.map +1 -0
- package/dist/code-paths/function-row.js +77 -0
- package/dist/code-paths/function-row.js.map +1 -0
- package/dist/code-paths/graph-controls.d.ts +27 -0
- package/dist/code-paths/graph-controls.d.ts.map +1 -0
- package/dist/code-paths/graph-controls.js +257 -0
- package/dist/code-paths/graph-controls.js.map +1 -0
- package/dist/code-paths/graph-scc.d.ts +32 -0
- package/dist/code-paths/graph-scc.d.ts.map +1 -0
- package/dist/code-paths/graph-scc.js +136 -0
- package/dist/code-paths/graph-scc.js.map +1 -0
- package/dist/code-paths/graph-stylesheet.d.ts +22 -0
- package/dist/code-paths/graph-stylesheet.d.ts.map +1 -0
- package/dist/code-paths/graph-stylesheet.js +121 -0
- package/dist/code-paths/graph-stylesheet.js.map +1 -0
- package/dist/code-paths/graph-view-model.d.ts +120 -0
- package/dist/code-paths/graph-view-model.d.ts.map +1 -0
- package/dist/code-paths/graph-view-model.js +199 -0
- package/dist/code-paths/graph-view-model.js.map +1 -0
- package/dist/code-paths/help-drawer.d.ts +18 -0
- package/dist/code-paths/help-drawer.d.ts.map +1 -0
- package/dist/code-paths/help-drawer.js +54 -0
- package/dist/code-paths/help-drawer.js.map +1 -0
- package/dist/code-paths/indexes.d.ts +28 -0
- package/dist/code-paths/indexes.d.ts.map +1 -0
- package/dist/code-paths/indexes.js +97 -0
- package/dist/code-paths/indexes.js.map +1 -0
- package/dist/code-paths/path-utils.d.ts +15 -0
- package/dist/code-paths/path-utils.d.ts.map +1 -0
- package/dist/code-paths/path-utils.js +47 -0
- package/dist/code-paths/path-utils.js.map +1 -0
- package/dist/code-paths/search.d.ts +14 -0
- package/dist/code-paths/search.d.ts.map +1 -0
- package/dist/code-paths/search.js +54 -0
- package/dist/code-paths/search.js.map +1 -0
- package/dist/code-paths/trace.d.ts +11 -0
- package/dist/code-paths/trace.d.ts.map +1 -0
- package/dist/code-paths/trace.js +60 -0
- package/dist/code-paths/trace.js.map +1 -0
- package/dist/code-paths/view-coupling.d.ts +22 -0
- package/dist/code-paths/view-coupling.d.ts.map +1 -0
- package/dist/code-paths/view-coupling.js +218 -0
- package/dist/code-paths/view-coupling.js.map +1 -0
- package/dist/code-paths/view-distribution.d.ts +20 -0
- package/dist/code-paths/view-distribution.d.ts.map +1 -0
- package/dist/code-paths/view-distribution.js +82 -0
- package/dist/code-paths/view-distribution.js.map +1 -0
- package/dist/code-paths/view-graph.d.ts +35 -0
- package/dist/code-paths/view-graph.d.ts.map +1 -0
- package/dist/code-paths/view-graph.js +379 -0
- package/dist/code-paths/view-graph.js.map +1 -0
- package/dist/code-paths/view-template.d.ts +154 -0
- package/dist/code-paths/view-template.d.ts.map +1 -0
- package/dist/code-paths/view-template.js +218 -0
- package/dist/code-paths/view-template.js.map +1 -0
- package/dist/code-paths/views-registry.d.ts +13 -0
- package/dist/code-paths/views-registry.d.ts.map +1 -0
- package/dist/code-paths/views-registry.js +53 -0
- package/dist/code-paths/views-registry.js.map +1 -0
- package/dist/code-paths.d.ts +69 -0
- package/dist/code-paths.d.ts.map +1 -0
- package/dist/code-paths.js +356 -0
- package/dist/code-paths.js.map +1 -0
- package/dist/css/cards.d.ts +9 -0
- package/dist/css/cards.d.ts.map +1 -0
- package/dist/css/cards.js +36 -0
- package/dist/css/cards.js.map +1 -0
- package/dist/css/code-paths.d.ts +9 -0
- package/dist/css/code-paths.d.ts.map +1 -0
- package/dist/css/code-paths.js +111 -0
- package/dist/css/code-paths.js.map +1 -0
- package/dist/css/data-table.d.ts +12 -0
- package/dist/css/data-table.d.ts.map +1 -0
- package/dist/css/data-table.js +103 -0
- package/dist/css/data-table.js.map +1 -0
- package/dist/css/function-card.d.ts +6 -0
- package/dist/css/function-card.d.ts.map +1 -0
- package/dist/css/function-card.js +26 -0
- package/dist/css/function-card.js.map +1 -0
- package/dist/css/help-drawer.d.ts +6 -0
- package/dist/css/help-drawer.d.ts.map +1 -0
- package/dist/css/help-drawer.js +22 -0
- package/dist/css/help-drawer.js.map +1 -0
- package/dist/css/tabs.d.ts +9 -0
- package/dist/css/tabs.d.ts.map +1 -0
- package/dist/css/tabs.js +28 -0
- package/dist/css/tabs.js.map +1 -0
- package/dist/css/theme.d.ts +8 -0
- package/dist/css/theme.d.ts.map +1 -0
- package/dist/css/theme.js +34 -0
- package/dist/css/theme.js.map +1 -0
- package/dist/css.d.ts +13 -0
- package/dist/css.d.ts.map +1 -0
- package/dist/css.js +30 -0
- package/dist/css.js.map +1 -0
- package/dist/generator.d.ts +33 -0
- package/dist/generator.d.ts.map +1 -0
- package/dist/generator.js +161 -0
- package/dist/generator.js.map +1 -0
- package/dist/index.d.ts +21 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/index.js.map +1 -0
- package/dist/overview.d.ts +13 -0
- package/dist/overview.d.ts.map +1 -0
- package/dist/overview.js +91 -0
- package/dist/overview.js.map +1 -0
- package/dist/recipes.d.ts +6 -0
- package/dist/recipes.d.ts.map +1 -0
- package/dist/recipes.js +68 -0
- package/dist/recipes.js.map +1 -0
- package/dist/sessions.d.ts +6 -0
- package/dist/sessions.d.ts.map +1 -0
- package/dist/sessions.js +288 -0
- package/dist/sessions.js.map +1 -0
- package/dist/shared/el.d.ts +13 -0
- package/dist/shared/el.d.ts.map +1 -0
- package/dist/shared/el.js +27 -0
- package/dist/shared/el.js.map +1 -0
- package/dist/shared/pagination.d.ts +15 -0
- package/dist/shared/pagination.d.ts.map +1 -0
- package/dist/shared/pagination.js +113 -0
- package/dist/shared/pagination.js.map +1 -0
- package/dist/shared/sortable.d.ts +14 -0
- package/dist/shared/sortable.d.ts.map +1 -0
- package/dist/shared/sortable.js +101 -0
- package/dist/shared/sortable.js.map +1 -0
- package/dist/shared/tab-activators.d.ts +16 -0
- package/dist/shared/tab-activators.d.ts.map +1 -0
- package/dist/shared/tab-activators.js +33 -0
- package/dist/shared/tab-activators.js.map +1 -0
- package/dist/shared/tab-bar.d.ts +8 -0
- package/dist/shared/tab-bar.d.ts.map +1 -0
- package/dist/shared/tab-bar.js +20 -0
- package/dist/shared/tab-bar.js.map +1 -0
- package/dist/shared.d.ts +26 -0
- package/dist/shared.d.ts.map +1 -0
- package/dist/shared.js +39 -0
- package/dist/shared.js.map +1 -0
- package/dist/subtab-bar.d.ts +23 -0
- package/dist/subtab-bar.d.ts.map +1 -0
- package/dist/subtab-bar.js +77 -0
- package/dist/subtab-bar.js.map +1 -0
- package/dist/tool-tab-registry.d.ts +76 -0
- package/dist/tool-tab-registry.d.ts.map +1 -0
- package/dist/tool-tab-registry.js +44 -0
- package/dist/tool-tab-registry.js.map +1 -0
- package/dist/tool-tabs-registrations.d.ts +19 -0
- package/dist/tool-tabs-registrations.d.ts.map +1 -0
- package/dist/tool-tabs-registrations.js +46 -0
- package/dist/tool-tabs-registrations.js.map +1 -0
- package/dist/tool-tabs.d.ts +12 -0
- package/dist/tool-tabs.d.ts.map +1 -0
- package/dist/tool-tabs.js +80 -0
- package/dist/tool-tabs.js.map +1 -0
- package/dist/vendor/cytoscape-bundle.js +600 -0
- package/package.json +52 -0
package/dist/checks.js
ADDED
|
@@ -0,0 +1,283 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Checks catalog rendering — browsable catalog of checks with run stats.
|
|
3
|
+
* Reusable: renderChecksCatalog(container, catalogData) can be called from any panel.
|
|
4
|
+
* Returns JS code as a string.
|
|
5
|
+
*/
|
|
6
|
+
export function dashboardChecksJs() {
|
|
7
|
+
return `
|
|
8
|
+
// =======================================================
|
|
9
|
+
// CHECKS CATALOG
|
|
10
|
+
// =======================================================
|
|
11
|
+
|
|
12
|
+
function computeCheckStats() {
|
|
13
|
+
const stats = {};
|
|
14
|
+
for (const s of sessions) {
|
|
15
|
+
// Per-session detail lives in the tool-owned opaque payload; fitness
|
|
16
|
+
// sessions carry { summary, checks }. Sessions without checks (graph,
|
|
17
|
+
// sim) contribute nothing here.
|
|
18
|
+
const checks = (s.payload && s.payload.checks) || [];
|
|
19
|
+
for (const ch of checks) {
|
|
20
|
+
if (!stats[ch.checkSlug]) stats[ch.checkSlug] = { runs: 0, passed: 0, failed: 0, lastRun: null };
|
|
21
|
+
const st = stats[ch.checkSlug];
|
|
22
|
+
st.runs++;
|
|
23
|
+
if (ch.passed) st.passed++; else st.failed++;
|
|
24
|
+
if (!st.lastRun || s.startedAt > st.lastRun) st.lastRun = s.startedAt;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return stats;
|
|
28
|
+
}
|
|
29
|
+
const checkStats = computeCheckStats();
|
|
30
|
+
|
|
31
|
+
/** Render longDescription as DOM nodes with bold and code formatting. Safe — no innerHTML. */
|
|
32
|
+
function renderLongDesc(text) {
|
|
33
|
+
const container = document.createElement('div');
|
|
34
|
+
container.className = 'check-long-desc';
|
|
35
|
+
if (!text) return container;
|
|
36
|
+
const parts = text.split(/(\\*\\*[^*]+\\*\\*|\\\`[^\\\`]+\\\`|\\n)/g);
|
|
37
|
+
parts.forEach(part => {
|
|
38
|
+
if (part === '\\n') {
|
|
39
|
+
container.appendChild(document.createElement('br'));
|
|
40
|
+
} else if (part.startsWith('**') && part.endsWith('**')) {
|
|
41
|
+
const strong = document.createElement('strong');
|
|
42
|
+
strong.textContent = part.slice(2, -2);
|
|
43
|
+
container.appendChild(strong);
|
|
44
|
+
} else if (part.startsWith('\\\`') && part.endsWith('\\\`')) {
|
|
45
|
+
const code = document.createElement('code');
|
|
46
|
+
code.textContent = part.slice(1, -1);
|
|
47
|
+
container.appendChild(code);
|
|
48
|
+
} else {
|
|
49
|
+
container.appendChild(document.createTextNode(part));
|
|
50
|
+
}
|
|
51
|
+
});
|
|
52
|
+
return container;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Render a check catalog table into any container element.
|
|
57
|
+
* @param panel - DOM element to render into
|
|
58
|
+
* @param catalogData - array of check catalog entries
|
|
59
|
+
*/
|
|
60
|
+
function renderChecksCatalog(panel, catalogData) {
|
|
61
|
+
if (!catalogData.length) {
|
|
62
|
+
panel.appendChild(el('div', {class:'empty', text:'No checks registered.'}));
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const allTags = new Set();
|
|
67
|
+
catalogData.forEach(c => (c.tags || []).forEach(t => allTags.add(t)));
|
|
68
|
+
const sortedTags = Array.from(allTags).sort();
|
|
69
|
+
|
|
70
|
+
// Filter bar
|
|
71
|
+
const filterBar = el('div', {class:'filter-bar'});
|
|
72
|
+
const searchInput = el('input', {class:'search-input', type:'text', placeholder:'Search checks...'});
|
|
73
|
+
const tagSelect = el('select', {class:'filter-select'});
|
|
74
|
+
tagSelect.appendChild(el('option', {value:'', text:'All tags'}));
|
|
75
|
+
sortedTags.forEach(t => tagSelect.appendChild(el('option', {value:t, text:t})));
|
|
76
|
+
const sourceSelect = el('select', {class:'filter-select'});
|
|
77
|
+
['', 'built-in', 'community'].forEach(v => {
|
|
78
|
+
sourceSelect.appendChild(el('option', {value:v, text: v || 'All sources'}));
|
|
79
|
+
});
|
|
80
|
+
filterBar.appendChild(searchInput);
|
|
81
|
+
filterBar.appendChild(tagSelect);
|
|
82
|
+
filterBar.appendChild(sourceSelect);
|
|
83
|
+
panel.appendChild(filterBar);
|
|
84
|
+
|
|
85
|
+
// Stats summary
|
|
86
|
+
const totalChecks = catalogData.length;
|
|
87
|
+
const builtinCount = catalogData.filter(c => c.source === 'built-in').length;
|
|
88
|
+
const communityCount = catalogData.filter(c => c.source === 'community').length;
|
|
89
|
+
const statsRow = el('div', {style:'display:flex;gap:16px;margin-bottom:16px;font-size:13px;color:var(--text-muted)'});
|
|
90
|
+
statsRow.appendChild(el('span', {text: totalChecks + ' total checks'}));
|
|
91
|
+
statsRow.appendChild(el('span', {text: builtinCount + ' built-in', style:'color:var(--accent)'}));
|
|
92
|
+
if (communityCount > 0) statsRow.appendChild(el('span', {text: communityCount + ' community', style:'color:var(--accent-sim)'}));
|
|
93
|
+
panel.appendChild(statsRow);
|
|
94
|
+
|
|
95
|
+
// Table
|
|
96
|
+
const table = el('table', {class:'data-table sortable'});
|
|
97
|
+
const thead = el('thead');
|
|
98
|
+
const headerRow = el('tr');
|
|
99
|
+
['', 'Check', 'Tags', 'Confidence', 'Source', 'Runs', 'Pass Rate', 'Last Run'].forEach(h => {
|
|
100
|
+
headerRow.appendChild(el('th', {text: h}));
|
|
101
|
+
});
|
|
102
|
+
thead.appendChild(headerRow);
|
|
103
|
+
table.appendChild(thead);
|
|
104
|
+
|
|
105
|
+
const tbody = el('tbody');
|
|
106
|
+
const sorted = [...catalogData].sort((a, b) => a.slug.localeCompare(b.slug));
|
|
107
|
+
const uid = 'cc-' + Math.random().toString(36).slice(2, 8);
|
|
108
|
+
|
|
109
|
+
sorted.forEach((check, i) => {
|
|
110
|
+
const st = checkStats[check.slug] || { runs: 0, passed: 0, failed: 0, lastRun: null };
|
|
111
|
+
const rate = st.runs > 0 ? Math.round((st.passed / st.runs) * 100) : -1;
|
|
112
|
+
const hasDesc = !!check.longDescription;
|
|
113
|
+
const expanderId = uid + '-exp-' + i;
|
|
114
|
+
|
|
115
|
+
const arrowCell = el('td', {style:'width:24px;text-align:center;color:var(--text-dim);font-size:12px'});
|
|
116
|
+
if (hasDesc) arrowCell.textContent = '\\u25B6';
|
|
117
|
+
|
|
118
|
+
const row = el('tr', {
|
|
119
|
+
class: hasDesc ? 'clickable' : '',
|
|
120
|
+
'data-slug': check.slug,
|
|
121
|
+
'data-tags': (check.tags || []).join(','),
|
|
122
|
+
'data-source': check.source,
|
|
123
|
+
'data-name': check.name.toLowerCase(),
|
|
124
|
+
onclick: hasDesc ? () => {
|
|
125
|
+
const exp = document.getElementById(expanderId);
|
|
126
|
+
if (exp) {
|
|
127
|
+
const isOpen = exp.classList.toggle('open');
|
|
128
|
+
exp.style.display = isOpen ? 'table-row' : 'none';
|
|
129
|
+
arrowCell.textContent = isOpen ? '\\u25BC' : '\\u25B6';
|
|
130
|
+
}
|
|
131
|
+
row.classList.toggle('expanded');
|
|
132
|
+
} : undefined
|
|
133
|
+
});
|
|
134
|
+
row.appendChild(arrowCell);
|
|
135
|
+
|
|
136
|
+
const nameCell = el('td', {style:'font-weight:500'});
|
|
137
|
+
nameCell.appendChild(document.createTextNode(check.slug));
|
|
138
|
+
row.appendChild(nameCell);
|
|
139
|
+
|
|
140
|
+
const tagsCell = el('td');
|
|
141
|
+
(check.tags || []).slice(0, 4).forEach(t => {
|
|
142
|
+
tagsCell.appendChild(el('span', {class:'tag-badge', text:t}));
|
|
143
|
+
});
|
|
144
|
+
if ((check.tags || []).length > 4) {
|
|
145
|
+
tagsCell.appendChild(el('span', {class:'tag-badge', text:'+' + ((check.tags || []).length - 4)}));
|
|
146
|
+
}
|
|
147
|
+
row.appendChild(tagsCell);
|
|
148
|
+
|
|
149
|
+
const confCell = el('td');
|
|
150
|
+
confCell.appendChild(el('span', {class:'badge badge-' + check.confidence, text: check.confidence}));
|
|
151
|
+
row.appendChild(confCell);
|
|
152
|
+
|
|
153
|
+
const sourceCell = el('td');
|
|
154
|
+
const sourceStyle = check.source === 'built-in' ? 'color:var(--accent)' : 'color:var(--accent-sim)';
|
|
155
|
+
sourceCell.appendChild(el('span', {text: check.source, style: sourceStyle + ';font-size:12px'}));
|
|
156
|
+
row.appendChild(sourceCell);
|
|
157
|
+
|
|
158
|
+
row.appendChild(el('td', {text: st.runs > 0 ? '' + st.runs : '\\u2014', style:'color:var(--text-dim)'}));
|
|
159
|
+
|
|
160
|
+
const rateCell = el('td');
|
|
161
|
+
if (rate >= 0) {
|
|
162
|
+
const rateColor = rate >= 90 ? 'var(--success)' : rate >= 70 ? 'var(--warning)' : 'var(--error)';
|
|
163
|
+
const bar = el('span', {class:'pass-rate-bar'});
|
|
164
|
+
const track = el('span', {class:'pass-rate-track'});
|
|
165
|
+
track.appendChild(el('span', {class:'pass-rate-fill', style:'width:' + rate + '%;background:' + rateColor}));
|
|
166
|
+
bar.appendChild(track);
|
|
167
|
+
bar.appendChild(el('span', {text: rate + '%', style:'font-size:12px;color:' + rateColor}));
|
|
168
|
+
rateCell.appendChild(bar);
|
|
169
|
+
} else {
|
|
170
|
+
rateCell.textContent = '\\u2014';
|
|
171
|
+
rateCell.style.color = 'var(--text-dim)';
|
|
172
|
+
}
|
|
173
|
+
row.appendChild(rateCell);
|
|
174
|
+
|
|
175
|
+
row.appendChild(el('td', {
|
|
176
|
+
text: st.lastRun ? new Date(st.lastRun).toLocaleDateString() : '\\u2014',
|
|
177
|
+
style:'color:var(--text-dim);font-size:12px'
|
|
178
|
+
}));
|
|
179
|
+
|
|
180
|
+
tbody.appendChild(row);
|
|
181
|
+
|
|
182
|
+
if (hasDesc) {
|
|
183
|
+
const expRow = el('tr', {id: expanderId, class:'expander-row', 'data-slug': check.slug, 'data-tags': (check.tags || []).join(','), 'data-source': check.source, 'data-name': check.name.toLowerCase()});
|
|
184
|
+
const expCell = el('td', {colspan:'8', style:'padding:0'});
|
|
185
|
+
const expContent = el('div', {class:'expander-content'});
|
|
186
|
+
expContent.appendChild(renderLongDesc(check.longDescription));
|
|
187
|
+
expCell.appendChild(expContent);
|
|
188
|
+
expRow.appendChild(expCell);
|
|
189
|
+
tbody.appendChild(expRow);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
table.appendChild(tbody);
|
|
194
|
+
const pag = el('div', {class:'pagination'});
|
|
195
|
+
const card = el('div', {class:'card'}, [table, pag]);
|
|
196
|
+
panel.appendChild(card);
|
|
197
|
+
|
|
198
|
+
const emptyMsg = el('div', {class:'empty', style:'display:none', text:'No checks match your filters.'});
|
|
199
|
+
card.insertBefore(emptyMsg, pag);
|
|
200
|
+
paginateGroupedRows(tbody, pag, 10);
|
|
201
|
+
|
|
202
|
+
function applyFilters() {
|
|
203
|
+
const search = searchInput.value.toLowerCase();
|
|
204
|
+
const tag = tagSelect.value;
|
|
205
|
+
const source = sourceSelect.value;
|
|
206
|
+
const allRows = Array.from(tbody.children);
|
|
207
|
+
let visibleCount = 0;
|
|
208
|
+
|
|
209
|
+
// First pass: mark rows visible/hidden and collapse expanders
|
|
210
|
+
for (let i = 0; i < allRows.length; i++) {
|
|
211
|
+
const row = allRows[i];
|
|
212
|
+
if (row.classList.contains('expander-row')) continue;
|
|
213
|
+
const slug = row.getAttribute('data-slug') || '';
|
|
214
|
+
const name = row.getAttribute('data-name') || '';
|
|
215
|
+
const rowTags = row.getAttribute('data-tags') || '';
|
|
216
|
+
const rowSource = row.getAttribute('data-source') || '';
|
|
217
|
+
const matchSearch = !search || slug.includes(search) || name.includes(search);
|
|
218
|
+
const matchTag = !tag || rowTags.split(',').includes(tag);
|
|
219
|
+
const matchSource = !source || rowSource === source;
|
|
220
|
+
const visible = matchSearch && matchTag && matchSource;
|
|
221
|
+
row.style.display = visible ? '' : 'none';
|
|
222
|
+
row._filterVisible = visible;
|
|
223
|
+
if (visible) visibleCount++;
|
|
224
|
+
if (i + 1 < allRows.length && allRows[i + 1].classList.contains('expander-row')) {
|
|
225
|
+
allRows[i + 1].style.display = 'none';
|
|
226
|
+
allRows[i + 1].classList.remove('open');
|
|
227
|
+
if (row.classList.contains('expanded')) {
|
|
228
|
+
row.classList.remove('expanded');
|
|
229
|
+
const arrowTd = row.children[0];
|
|
230
|
+
if (arrowTd) arrowTd.textContent = '\\u25B6';
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
emptyMsg.style.display = visibleCount === 0 ? '' : 'none';
|
|
235
|
+
|
|
236
|
+
// Re-paginate only visible rows
|
|
237
|
+
const hasFilters = search || tag || source;
|
|
238
|
+
if (hasFilters) {
|
|
239
|
+
// Hide all first, then paginate only matching groups
|
|
240
|
+
const groups = [];
|
|
241
|
+
for (let i = 0; i < allRows.length; i++) {
|
|
242
|
+
const row = allRows[i];
|
|
243
|
+
if (row.classList.contains('expander-row')) continue;
|
|
244
|
+
if (!row._filterVisible) continue;
|
|
245
|
+
const group = [row];
|
|
246
|
+
if (i + 1 < allRows.length && allRows[i+1].classList.contains('expander-row')) {
|
|
247
|
+
group.push(allRows[i+1]);
|
|
248
|
+
}
|
|
249
|
+
groups.push(group);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Custom pagination for filtered results
|
|
253
|
+
let currentPage = 0;
|
|
254
|
+
const pageSize = 10;
|
|
255
|
+
const totalPages = Math.max(1, Math.ceil(groups.length / pageSize));
|
|
256
|
+
|
|
257
|
+
function renderFilteredPage() {
|
|
258
|
+
// Hide all filtered rows first
|
|
259
|
+
groups.forEach(g => g.forEach(r => { r.style.display = 'none'; }));
|
|
260
|
+
const start = currentPage * pageSize;
|
|
261
|
+
const end = start + pageSize;
|
|
262
|
+
groups.slice(start, end).forEach(g => { g[0].style.display = ''; });
|
|
263
|
+
|
|
264
|
+
while (pag.firstChild) pag.removeChild(pag.firstChild);
|
|
265
|
+
if (groups.length <= pageSize) return;
|
|
266
|
+
pag.appendChild(el('div', {class:'pagination-info', text: 'Showing ' + (start+1) + '-' + Math.min(end, groups.length) + ' of ' + groups.length + ' checks'}));
|
|
267
|
+
const btns = el('div', {class:'pagination-btns'});
|
|
268
|
+
renderPageButtons(btns, currentPage, totalPages, (p) => { currentPage = p; renderFilteredPage(); });
|
|
269
|
+
pag.appendChild(btns);
|
|
270
|
+
}
|
|
271
|
+
renderFilteredPage();
|
|
272
|
+
} else {
|
|
273
|
+
paginateGroupedRows(tbody, pag, 10);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
searchInput.addEventListener('input', applyFilters);
|
|
278
|
+
tagSelect.addEventListener('change', applyFilters);
|
|
279
|
+
sourceSelect.addEventListener('change', applyFilters);
|
|
280
|
+
}
|
|
281
|
+
`;
|
|
282
|
+
}
|
|
283
|
+
//# sourceMappingURL=checks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"checks.js","sourceRoot":"","sources":["../src/checks.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,UAAU,iBAAiB;IAC/B,OAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkRR,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Restructured Code Paths explore-tab set (Plan D — shipped).
|
|
3
|
+
*
|
|
4
|
+
* The explore-tab restructure has shipped: `dashboardCodePathsJs` emits exactly
|
|
5
|
+
* the kept views (graph / coupling) plus the ranked-distribution "Functions"
|
|
6
|
+
* affordance, and the single-metric / standalone-SCC view sources were deleted.
|
|
7
|
+
* The former standalone Search subtab was folded into the Functions view as an
|
|
8
|
+
* in-table name filter, so it no longer registers a `search` view.
|
|
9
|
+
* The emitter no longer has a legacy branch — the `restructured` parameter is a
|
|
10
|
+
* vestigial test-seam arg that always yields the restructured set.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=views-registry.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views-registry.test.d.ts","sourceRoot":"","sources":["../../../src/code-paths/__tests__/views-registry.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Restructured Code Paths explore-tab set (Plan D — shipped).
|
|
3
|
+
*
|
|
4
|
+
* The explore-tab restructure has shipped: `dashboardCodePathsJs` emits exactly
|
|
5
|
+
* the kept views (graph / coupling) plus the ranked-distribution "Functions"
|
|
6
|
+
* affordance, and the single-metric / standalone-SCC view sources were deleted.
|
|
7
|
+
* The former standalone Search subtab was folded into the Functions view as an
|
|
8
|
+
* in-table name filter, so it no longer registers a `search` view.
|
|
9
|
+
* The emitter no longer has a legacy branch — the `restructured` parameter is a
|
|
10
|
+
* vestigial test-seam arg that always yields the restructured set.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, it } from 'vitest';
|
|
13
|
+
import { dashboardCodePathsJs } from '../../code-paths.js';
|
|
14
|
+
/** Pull every `id: '<x>'` from a `views.push({ id: '<x>' ... })` literal. */
|
|
15
|
+
function registeredViewIds(js) {
|
|
16
|
+
const ids = [];
|
|
17
|
+
// Split on the literal `views.push({` boundary, then match the first `id:`
|
|
18
|
+
// in each chunk. Avoids a backtracking-prone whitespace pattern.
|
|
19
|
+
const chunks = js.split('views.push({');
|
|
20
|
+
for (let i = 1; i < chunks.length; i++) {
|
|
21
|
+
const m = /id:\s*'([a-z-]+)'/.exec(chunks[i] ?? '');
|
|
22
|
+
if (m)
|
|
23
|
+
ids.push(m[1]);
|
|
24
|
+
}
|
|
25
|
+
return ids;
|
|
26
|
+
}
|
|
27
|
+
describe('Code Paths explore-tab set', () => {
|
|
28
|
+
it('emitter registers exactly {graph, coupling, distribution}', () => {
|
|
29
|
+
const ids = registeredViewIds(dashboardCodePathsJs());
|
|
30
|
+
expect(new Set(ids)).toEqual(new Set(['graph', 'coupling', 'distribution']));
|
|
31
|
+
});
|
|
32
|
+
it('drops the single-metric + standalone-SCC + standalone-search views', () => {
|
|
33
|
+
const ids = registeredViewIds(dashboardCodePathsJs());
|
|
34
|
+
for (const removed of ['big', 'hot', 'wide', 'untested', 'sccs', 'search']) {
|
|
35
|
+
expect(ids).not.toContain(removed);
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
});
|
|
39
|
+
//# sourceMappingURL=views-registry.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views-registry.test.js","sourceRoot":"","sources":["../../../src/code-paths/__tests__/views-registry.test.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE9C,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAE3D,6EAA6E;AAC7E,SAAS,iBAAiB,CAAC,EAAU;IACnC,MAAM,GAAG,GAAa,EAAE,CAAC;IACzB,2EAA2E;IAC3E,iEAAiE;IACjE,MAAM,MAAM,GAAG,EAAE,CAAC,KAAK,CAAC,cAAc,CAAC,CAAC;IACxC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACvC,MAAM,CAAC,GAAG,mBAAmB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC;QACpD,IAAI,CAAC;YAAE,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,EAAE,CAAC,2DAA2D,EAAE,GAAG,EAAE;QACnE,MAAM,GAAG,GAAG,iBAAiB,CAAC,oBAAoB,EAAE,CAAC,CAAC;QACtD,MAAM,CAAC,IAAI,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,GAAG,CAAC,CAAC,OAAO,EAAE,UAAU,EAAE,cAAc,CAAC,CAAC,CAAC,CAAC;IAC/E,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oEAAoE,EAAE,GAAG,EAAE;QAC5E,MAAM,GAAG,GAAG,iBAAiB,CAAC,oBAAoB,EAAE,CAAC,CAAC;QACtD,KAAK,MAAM,OAAO,IAAI,CAAC,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;YAC3E,MAAM,CAAC,GAAG,CAAC,CAAC,GAAG,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QACrC,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog provenance bar for the Explore tab.
|
|
3
|
+
*
|
|
4
|
+
* The Explore views (Coupling / Functions / Visualization) all render from the
|
|
5
|
+
* single cached graph catalog — the LATEST `graph` build, whatever its scope.
|
|
6
|
+
* A scoped run (`graph packages/contracts`) or a stale build therefore narrows
|
|
7
|
+
* every view, with no on-page indication. Without a provenance line a
|
|
8
|
+
* single-package catalog reads as "the tool is broken" instead of "this catalog
|
|
9
|
+
* only covers one package."
|
|
10
|
+
*
|
|
11
|
+
* This bar surfaces what the views are built from — package scope, function
|
|
12
|
+
* count, build time, and engine — so a scoped/stale catalog is self-explanatory.
|
|
13
|
+
* Every value is DERIVED from the embedded catalog itself, so it is ground truth
|
|
14
|
+
* and can never drift from what the views render (no separately-persisted
|
|
15
|
+
* "scope" field to fall out of sync).
|
|
16
|
+
*
|
|
17
|
+
* Declares the top-level `renderCatalogProvenance(host, catalog)` consumed by
|
|
18
|
+
* the Explore body. Depends on `packagesInCatalog` (filters.ts) and the shared
|
|
19
|
+
* `el` helper, so it must be concatenated AFTER filters.ts in the prelude.
|
|
20
|
+
*/
|
|
21
|
+
export declare function dashboardCatalogProvenanceJs(): string;
|
|
22
|
+
//# sourceMappingURL=catalog-provenance.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-provenance.d.ts","sourceRoot":"","sources":["../../src/code-paths/catalog-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,wBAAgB,4BAA4B,IAAI,MAAM,CAsFrD"}
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog provenance bar for the Explore tab.
|
|
3
|
+
*
|
|
4
|
+
* The Explore views (Coupling / Functions / Visualization) all render from the
|
|
5
|
+
* single cached graph catalog — the LATEST `graph` build, whatever its scope.
|
|
6
|
+
* A scoped run (`graph packages/contracts`) or a stale build therefore narrows
|
|
7
|
+
* every view, with no on-page indication. Without a provenance line a
|
|
8
|
+
* single-package catalog reads as "the tool is broken" instead of "this catalog
|
|
9
|
+
* only covers one package."
|
|
10
|
+
*
|
|
11
|
+
* This bar surfaces what the views are built from — package scope, function
|
|
12
|
+
* count, build time, and engine — so a scoped/stale catalog is self-explanatory.
|
|
13
|
+
* Every value is DERIVED from the embedded catalog itself, so it is ground truth
|
|
14
|
+
* and can never drift from what the views render (no separately-persisted
|
|
15
|
+
* "scope" field to fall out of sync).
|
|
16
|
+
*
|
|
17
|
+
* Declares the top-level `renderCatalogProvenance(host, catalog)` consumed by
|
|
18
|
+
* the Explore body. Depends on `packagesInCatalog` (filters.ts) and the shared
|
|
19
|
+
* `el` helper, so it must be concatenated AFTER filters.ts in the prelude.
|
|
20
|
+
*/
|
|
21
|
+
export function dashboardCatalogProvenanceJs() {
|
|
22
|
+
return String.raw `
|
|
23
|
+
// Build engine ('sharded' | 'exact') parsed from the catalog cache key
|
|
24
|
+
// (e.g. "eng=0.1.0|mode=sharded|..."). Null when the marker is absent.
|
|
25
|
+
function catalogEngineMode(catalog) {
|
|
26
|
+
const m = /(?:^|\|)mode=([a-z]+)/.exec((catalog && catalog.cacheKey) || '');
|
|
27
|
+
return m ? m[1] : null;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Total function OCCURRENCES across the catalog (each occurrence is one graph
|
|
31
|
+
// node) — the catalog's size, not just distinct names.
|
|
32
|
+
function catalogFunctionCount(catalog) {
|
|
33
|
+
if (!catalog || !catalog.functions) return 0;
|
|
34
|
+
let n = 0;
|
|
35
|
+
for (const name of Object.keys(catalog.functions)) n += (catalog.functions[name] || []).length;
|
|
36
|
+
return n;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// Coarse "N <unit> ago" for the build time. Browser Date.now() is fine here
|
|
40
|
+
// (this is page JS, not the engine's Date.now()-free pure layer).
|
|
41
|
+
function provenanceRelTime(iso) {
|
|
42
|
+
const t = Date.parse(iso);
|
|
43
|
+
if (isNaN(t)) return '';
|
|
44
|
+
const secs = Math.max(0, Math.round((Date.now() - t) / 1000));
|
|
45
|
+
if (secs < 45) return 'just now';
|
|
46
|
+
const mins = Math.round(secs / 60);
|
|
47
|
+
if (mins < 60) return mins + ' min' + (mins !== 1 ? 's' : '') + ' ago';
|
|
48
|
+
const hrs = Math.round(mins / 60);
|
|
49
|
+
if (hrs < 24) return hrs + ' hour' + (hrs !== 1 ? 's' : '') + ' ago';
|
|
50
|
+
const days = Math.round(hrs / 24);
|
|
51
|
+
return days + ' day' + (days !== 1 ? 's' : '') + ' ago';
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function provenanceChip(label, value, opts) {
|
|
55
|
+
opts = opts || {};
|
|
56
|
+
const chip = el('span', { style: 'display:inline-flex;align-items:baseline;gap:6px' });
|
|
57
|
+
chip.appendChild(el('span', { text: label, style: 'color:var(--text-dim);font-size:10px;font-weight:600;text-transform:uppercase;letter-spacing:0.05em' }));
|
|
58
|
+
chip.appendChild(el('span', { text: value, title: opts.title || '', style: 'color:' + (opts.color || 'var(--text)') + ';font-weight:600;font-size:13px' }));
|
|
59
|
+
return chip;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
// Render the provenance bar into host. No-op when no catalog is loaded (the
|
|
63
|
+
// caller already shows a "No catalog yet." empty state in that case).
|
|
64
|
+
function renderCatalogProvenance(host, catalog) {
|
|
65
|
+
if (!catalog) return;
|
|
66
|
+
const pkgs = packagesInCatalog(catalog);
|
|
67
|
+
const fnCount = catalogFunctionCount(catalog);
|
|
68
|
+
const engine = catalogEngineMode(catalog);
|
|
69
|
+
const builtAt = catalog.builtAt ? new Date(catalog.builtAt) : null;
|
|
70
|
+
|
|
71
|
+
const bar = el('div', {
|
|
72
|
+
class: 'catalog-provenance',
|
|
73
|
+
style: 'display:flex;flex-wrap:wrap;align-items:center;gap:10px 20px;margin:0 0 16px;padding:10px 14px;border:1px solid var(--border);border-radius:8px;background:var(--bg-card)',
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Scope is the headline signal: 1 package vs the whole repo. List the names
|
|
77
|
+
// inline when the set is small (so a scoped build reads "1 package: contracts"
|
|
78
|
+
// directly); always carry the full sorted list in the title for hover.
|
|
79
|
+
const pkgLabel = pkgs.length === 1 ? '1 package' : String(pkgs.length) + ' packages';
|
|
80
|
+
const pkgNames = pkgs.length > 0 && pkgs.length <= 4 ? ': ' + pkgs.join(', ') : '';
|
|
81
|
+
bar.appendChild(
|
|
82
|
+
provenanceChip('Scope', pkgLabel + pkgNames, {
|
|
83
|
+
color: 'var(--accent)',
|
|
84
|
+
title: pkgs.join(', '),
|
|
85
|
+
}),
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
bar.appendChild(provenanceChip('Functions', fnCount.toLocaleString()));
|
|
89
|
+
|
|
90
|
+
if (builtAt && !isNaN(builtAt.getTime())) {
|
|
91
|
+
bar.appendChild(
|
|
92
|
+
provenanceChip('Built', provenanceRelTime(catalog.builtAt), { title: builtAt.toLocaleString() }),
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
if (engine) bar.appendChild(provenanceChip('Engine', engine));
|
|
97
|
+
|
|
98
|
+
// 'fast' resolution = syntactic (approximate) edges, so the coupling matrix /
|
|
99
|
+
// visualization are approximate too. 'exact' is the default and needs no flag.
|
|
100
|
+
if (catalog.resolutionMode === 'fast') {
|
|
101
|
+
bar.appendChild(provenanceChip('Resolution', 'fast (approximate)', { color: 'var(--warning)' }));
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
host.appendChild(bar);
|
|
105
|
+
}
|
|
106
|
+
`;
|
|
107
|
+
}
|
|
108
|
+
//# sourceMappingURL=catalog-provenance.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-provenance.js","sourceRoot":"","sources":["../../src/code-paths/catalog-provenance.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAEH,MAAM,UAAU,4BAA4B;IAC1C,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoFlB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Paths — Catalog & Recipes subtab tables.
|
|
3
|
+
*
|
|
4
|
+
* Declares the two top-level renderers the Code Paths panel mounts for its
|
|
5
|
+
* "Catalog" (graph rule catalog) and "Recipes" (graph recipe catalog) subtabs.
|
|
6
|
+
* Extracted from the panel orchestrator (code-paths.ts) to keep that aggregator
|
|
7
|
+
* focused on wiring; both functions are pure DOM table builders that close over
|
|
8
|
+
* the shared `el` helper, so they only need to be concatenated after it.
|
|
9
|
+
*/
|
|
10
|
+
export declare function dashboardCatalogRecipesTablesJs(): string;
|
|
11
|
+
//# sourceMappingURL=catalog-recipes-tables.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-recipes-tables.d.ts","sourceRoot":"","sources":["../../src/code-paths/catalog-recipes-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,wBAAgB,+BAA+B,IAAI,MAAM,CA2ExD"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Code Paths — Catalog & Recipes subtab tables.
|
|
3
|
+
*
|
|
4
|
+
* Declares the two top-level renderers the Code Paths panel mounts for its
|
|
5
|
+
* "Catalog" (graph rule catalog) and "Recipes" (graph recipe catalog) subtabs.
|
|
6
|
+
* Extracted from the panel orchestrator (code-paths.ts) to keep that aggregator
|
|
7
|
+
* focused on wiring; both functions are pure DOM table builders that close over
|
|
8
|
+
* the shared `el` helper, so they only need to be concatenated after it.
|
|
9
|
+
*/
|
|
10
|
+
export function dashboardCatalogRecipesTablesJs() {
|
|
11
|
+
return String.raw `
|
|
12
|
+
// =======================================================
|
|
13
|
+
// CODE PATHS — CATALOG SUBTAB (graph rule catalog)
|
|
14
|
+
// =======================================================
|
|
15
|
+
function renderGraphRuleCatalog(container, rulesData) {
|
|
16
|
+
if (!rulesData || !rulesData.length) {
|
|
17
|
+
container.appendChild(el('div', { class: 'empty', text: 'No rules available.' }));
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
const table = el('table', { class: 'data-table' });
|
|
21
|
+
const thead = el('thead');
|
|
22
|
+
const headerRow = el('tr');
|
|
23
|
+
['Rule', 'Default Severity', 'Source'].forEach(h => {
|
|
24
|
+
headerRow.appendChild(el('th', { text: h }));
|
|
25
|
+
});
|
|
26
|
+
thead.appendChild(headerRow);
|
|
27
|
+
table.appendChild(thead);
|
|
28
|
+
|
|
29
|
+
const tbody = el('tbody');
|
|
30
|
+
rulesData.forEach(rule => {
|
|
31
|
+
const row = el('tr');
|
|
32
|
+
row.appendChild(el('td', { text: rule.slug, style: 'font-weight:500' }));
|
|
33
|
+
const sevCell = el('td');
|
|
34
|
+
const sevColor = rule.defaultSeverity === 'error' ? 'color:var(--danger)' : 'color:var(--warning)';
|
|
35
|
+
sevCell.appendChild(el('span', { text: rule.defaultSeverity, style: sevColor + ';font-size:12px' }));
|
|
36
|
+
row.appendChild(sevCell);
|
|
37
|
+
const srcCell = el('td');
|
|
38
|
+
srcCell.appendChild(el('span', { class: 'badge', style: 'background:var(--bg-hover);color:var(--text-muted)', text: rule.source }));
|
|
39
|
+
row.appendChild(srcCell);
|
|
40
|
+
tbody.appendChild(row);
|
|
41
|
+
});
|
|
42
|
+
table.appendChild(tbody);
|
|
43
|
+
container.appendChild(el('div', { class: 'card' }, [table]));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
// =======================================================
|
|
47
|
+
// CODE PATHS — RECIPES SUBTAB (graph recipe catalog)
|
|
48
|
+
// =======================================================
|
|
49
|
+
function renderGraphRecipeCatalog(container, recipesData) {
|
|
50
|
+
if (!recipesData || !recipesData.length) {
|
|
51
|
+
container.appendChild(el('div', { class: 'empty', text: 'No recipes available.' }));
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
const table = el('table', { class: 'data-table' });
|
|
55
|
+
const thead = el('thead');
|
|
56
|
+
const headerRow = el('tr');
|
|
57
|
+
['Recipe', 'Description', 'Selector', 'Tags'].forEach(h => {
|
|
58
|
+
headerRow.appendChild(el('th', { text: h }));
|
|
59
|
+
});
|
|
60
|
+
thead.appendChild(headerRow);
|
|
61
|
+
table.appendChild(thead);
|
|
62
|
+
|
|
63
|
+
const tbody = el('tbody');
|
|
64
|
+
recipesData.forEach(recipe => {
|
|
65
|
+
const row = el('tr');
|
|
66
|
+
const nameCell = el('td', { style: 'font-weight:500' });
|
|
67
|
+
nameCell.appendChild(el('div', { text: recipe.displayName }));
|
|
68
|
+
nameCell.appendChild(el('div', { text: recipe.name, style: 'font-size:11px;color:var(--text-dim);font-weight:400' }));
|
|
69
|
+
row.appendChild(nameCell);
|
|
70
|
+
row.appendChild(el('td', { text: recipe.description, style: 'color:var(--text-muted)' }));
|
|
71
|
+
const selCell = el('td');
|
|
72
|
+
selCell.appendChild(el('span', { class: 'badge', style: 'background:var(--bg-hover);color:var(--text-muted)', text: recipe.selectorType }));
|
|
73
|
+
row.appendChild(selCell);
|
|
74
|
+
const tagsCell = el('td');
|
|
75
|
+
(recipe.tags || []).forEach(t => {
|
|
76
|
+
tagsCell.appendChild(el('span', { class: 'tag-badge', text: t }));
|
|
77
|
+
});
|
|
78
|
+
row.appendChild(tagsCell);
|
|
79
|
+
tbody.appendChild(row);
|
|
80
|
+
});
|
|
81
|
+
table.appendChild(tbody);
|
|
82
|
+
container.appendChild(el('div', { class: 'card' }, [table]));
|
|
83
|
+
}
|
|
84
|
+
`;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=catalog-recipes-tables.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog-recipes-tables.js","sourceRoot":"","sources":["../../src/code-paths/catalog-recipes-tables.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,UAAU,+BAA+B;IAC7C,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyElB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vendored Cytoscape emitter.
|
|
3
|
+
*
|
|
4
|
+
* Reads the committed `src/vendor/cytoscape-bundle.js` UMD blob at
|
|
5
|
+
* generation time and returns it as a JS string for inlining into the
|
|
6
|
+
* report's single `<script>` block. The bundle registers the `cytoscape`
|
|
7
|
+
* and `cytoscapeDagre` browser globals the Graph view (`view-graph.ts`)
|
|
8
|
+
* consumes — fully offline, no CDN, no network at view time.
|
|
9
|
+
*
|
|
10
|
+
* Architectural note: this module reads the bundle via `node:fs`, it does
|
|
11
|
+
* NOT `import 'cytoscape'`. That is deliberate — the `dashboard-no-ui-
|
|
12
|
+
* framework` dependency-cruiser rule forbids importing a visualization
|
|
13
|
+
* library into `packages/dashboard/src/`. The renderer reaches the report
|
|
14
|
+
* as committed source text, never as a module dependency. The `cytoscape`
|
|
15
|
+
* / `cytoscape-dagre` packages are devDependencies used only by the vendor
|
|
16
|
+
* build script (`scripts/vendor-cytoscape.mjs`), which lives outside
|
|
17
|
+
* `src/` and so is out of the rule's scope.
|
|
18
|
+
*/
|
|
19
|
+
/**
|
|
20
|
+
* Emit the vendored Cytoscape UMD bundle as a JS string for inlining.
|
|
21
|
+
*
|
|
22
|
+
* MUST be concatenated into the Code Paths script BEFORE any view emitter
|
|
23
|
+
* that references the `cytoscape` global (i.e. before
|
|
24
|
+
* `dashboardViewGraphJs()`).
|
|
25
|
+
*/
|
|
26
|
+
export declare function dashboardCytoscapeVendorJs(): string;
|
|
27
|
+
//# sourceMappingURL=cytoscape-vendor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cytoscape-vendor.d.ts","sourceRoot":"","sources":["../../src/code-paths/cytoscape-vendor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AA8CH;;;;;;GAMG;AACH,wBAAgB,0BAA0B,IAAI,MAAM,CAEnD"}
|