@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
|
@@ -0,0 +1,272 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* @vitest-environment jsdom
|
|
4
|
+
*
|
|
5
|
+
* Functions (distribution) view — the ranked-distribution affordance that
|
|
6
|
+
* also hosts the in-table name filter folded in from the former standalone
|
|
7
|
+
* Search subtab. Verifies the search input renders above the table and
|
|
8
|
+
* re-filters the rows in place by function simple-name.
|
|
9
|
+
*/
|
|
10
|
+
import { describe, expect, it, beforeEach } from 'vitest';
|
|
11
|
+
import { dashboardEditorLinkJs } from '../code-paths/editor-link.js';
|
|
12
|
+
import { dashboardFiltersJs } from '../code-paths/filters.js';
|
|
13
|
+
import { dashboardFunctionCardJs } from '../code-paths/function-card.js';
|
|
14
|
+
import { dashboardFunctionRowJs } from '../code-paths/function-row.js';
|
|
15
|
+
import { dashboardHelpDrawerJs } from '../code-paths/help-drawer.js';
|
|
16
|
+
import { dashboardIndexesJs } from '../code-paths/indexes.js';
|
|
17
|
+
import { dashboardPathUtilsJs } from '../code-paths/path-utils.js';
|
|
18
|
+
import { dashboardTraceJs } from '../code-paths/trace.js';
|
|
19
|
+
import { dashboardViewDistributionJs } from '../code-paths/view-distribution.js';
|
|
20
|
+
import { dashboardViewsRegistryJs } from '../code-paths/views-registry.js';
|
|
21
|
+
function loadEnv(catalog) {
|
|
22
|
+
const elSrc = `
|
|
23
|
+
function el(tag, attrs, children) {
|
|
24
|
+
const e = document.createElement(tag);
|
|
25
|
+
if (attrs) Object.entries(attrs).forEach(([k,v]) => {
|
|
26
|
+
if (k === 'text') e.textContent = v;
|
|
27
|
+
else if (k === 'class') e.className = v;
|
|
28
|
+
else if (k.startsWith('on')) e.addEventListener(k.slice(2), v);
|
|
29
|
+
else e.setAttribute(k, v);
|
|
30
|
+
});
|
|
31
|
+
if (children) children.forEach(c => { if (typeof c === 'string') e.appendChild(document.createTextNode(c)); else if (c) e.appendChild(c); });
|
|
32
|
+
return e;
|
|
33
|
+
}
|
|
34
|
+
var EDITOR_PROTOCOL = null;
|
|
35
|
+
`;
|
|
36
|
+
const tail = `
|
|
37
|
+
var graphCatalog = ${JSON.stringify(catalog)};
|
|
38
|
+
var graphIndexes = buildIndexes(graphCatalog);
|
|
39
|
+
return { views, graphCatalog, graphIndexes, filterState };
|
|
40
|
+
`;
|
|
41
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval, sonarjs/code-eval -- Trusted source.
|
|
42
|
+
const factory = new Function(elSrc +
|
|
43
|
+
dashboardPathUtilsJs() +
|
|
44
|
+
dashboardIndexesJs() +
|
|
45
|
+
dashboardViewsRegistryJs() +
|
|
46
|
+
dashboardFiltersJs() +
|
|
47
|
+
dashboardFunctionRowJs() +
|
|
48
|
+
dashboardHelpDrawerJs() +
|
|
49
|
+
dashboardEditorLinkJs() +
|
|
50
|
+
dashboardTraceJs() +
|
|
51
|
+
dashboardFunctionCardJs() +
|
|
52
|
+
dashboardViewDistributionJs() +
|
|
53
|
+
tail);
|
|
54
|
+
return factory();
|
|
55
|
+
}
|
|
56
|
+
function makeOcc(over) {
|
|
57
|
+
return {
|
|
58
|
+
qualifiedName: over.simpleName,
|
|
59
|
+
line: 1,
|
|
60
|
+
column: 0,
|
|
61
|
+
endLine: 5,
|
|
62
|
+
kind: 'function-declaration',
|
|
63
|
+
params: [],
|
|
64
|
+
returnType: null,
|
|
65
|
+
enclosingClass: null,
|
|
66
|
+
decorators: [],
|
|
67
|
+
visibility: 'exported',
|
|
68
|
+
inTestFile: false,
|
|
69
|
+
definedInGenerated: false,
|
|
70
|
+
calls: [],
|
|
71
|
+
...over,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
const catalog = {
|
|
75
|
+
version: '2.0',
|
|
76
|
+
tool: 'graph',
|
|
77
|
+
language: 'typescript',
|
|
78
|
+
builtAt: 'now',
|
|
79
|
+
functions: {
|
|
80
|
+
a: [makeOcc({ bodyHash: 'a', simpleName: 'validateInput', filePath: 'packages/cli/src/a.ts' })],
|
|
81
|
+
b: [makeOcc({ bodyHash: 'b', simpleName: 'renderTable', filePath: 'packages/cli/src/b.ts' })],
|
|
82
|
+
c: [makeOcc({ bodyHash: 'c', simpleName: 'parseConfig', filePath: 'packages/cli/src/c.ts' })],
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
function renderDistribution() {
|
|
86
|
+
const env = loadEnv(catalog);
|
|
87
|
+
const view = document.createElement('div');
|
|
88
|
+
env.views
|
|
89
|
+
.find((v) => v.id === 'distribution')
|
|
90
|
+
.render(view, env.graphCatalog, env.graphIndexes, env.filterState);
|
|
91
|
+
return { view };
|
|
92
|
+
}
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
document.body.innerHTML = '';
|
|
95
|
+
});
|
|
96
|
+
describe('Functions (distribution) view', () => {
|
|
97
|
+
it('renders a name-filter search input above the table', () => {
|
|
98
|
+
const { view } = renderDistribution();
|
|
99
|
+
const input = view.querySelector('#code-paths-search-distribution');
|
|
100
|
+
expect(input).not.toBeNull();
|
|
101
|
+
// The input must precede the rendered table in document order.
|
|
102
|
+
const firstRow = view.querySelector('[data-body-hash]');
|
|
103
|
+
expect(firstRow).not.toBeNull();
|
|
104
|
+
expect(input.compareDocumentPosition(firstRow) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
105
|
+
});
|
|
106
|
+
it('shows every function before any filtering', () => {
|
|
107
|
+
const { view } = renderDistribution();
|
|
108
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(3);
|
|
109
|
+
});
|
|
110
|
+
it('re-filters rows in place by simple-name substring', () => {
|
|
111
|
+
const { view } = renderDistribution();
|
|
112
|
+
const input = view.querySelector('#code-paths-search-distribution');
|
|
113
|
+
input.value = 'parse';
|
|
114
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
115
|
+
const rows = view.querySelectorAll('[data-body-hash]');
|
|
116
|
+
expect(rows.length).toBe(1);
|
|
117
|
+
expect(view.textContent).toContain('parseConfig');
|
|
118
|
+
expect(view.textContent).not.toContain('validateInput');
|
|
119
|
+
});
|
|
120
|
+
it('collapses to the empty state when nothing matches, and restores on clear', () => {
|
|
121
|
+
const { view } = renderDistribution();
|
|
122
|
+
const input = view.querySelector('#code-paths-search-distribution');
|
|
123
|
+
input.value = 'zzz-no-such-name';
|
|
124
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
125
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(0);
|
|
126
|
+
expect(view.querySelector('.empty')).not.toBeNull();
|
|
127
|
+
input.value = '';
|
|
128
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
129
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(3);
|
|
130
|
+
});
|
|
131
|
+
it('renders the "Functions (N)" heading with ⓘ ABOVE the controls (like Coupling/Visualization)', () => {
|
|
132
|
+
const { view } = renderDistribution();
|
|
133
|
+
const heading = view.querySelector('h3');
|
|
134
|
+
const info = view.querySelector('.section-info');
|
|
135
|
+
const controls = view.querySelector('.code-paths-ranked-controls');
|
|
136
|
+
expect(heading).not.toBeNull();
|
|
137
|
+
expect(heading.textContent).toContain('Functions (3)'); // 3 functions in the sample
|
|
138
|
+
expect(info).not.toBeNull();
|
|
139
|
+
expect(controls).not.toBeNull();
|
|
140
|
+
// The heading must precede the controls row in document order.
|
|
141
|
+
expect(heading.compareDocumentPosition(controls) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
142
|
+
});
|
|
143
|
+
it('updates the heading count as the filter narrows the rows', () => {
|
|
144
|
+
const { view } = renderDistribution();
|
|
145
|
+
const input = view.querySelector('#code-paths-search-distribution');
|
|
146
|
+
input.value = 'parse';
|
|
147
|
+
input.dispatchEvent(new Event('input', { bubbles: true }));
|
|
148
|
+
expect(view.querySelector('h3').textContent).toContain('Functions (1)');
|
|
149
|
+
});
|
|
150
|
+
it('renders Kind and Package single-select dropdowns before the search box', () => {
|
|
151
|
+
const { view } = renderDistribution();
|
|
152
|
+
const kind = view.querySelector('select[data-control="fn-kind"]');
|
|
153
|
+
const pkg = view.querySelector('select[data-control="fn-package"]');
|
|
154
|
+
const search = view.querySelector('#code-paths-search-distribution');
|
|
155
|
+
expect(kind).not.toBeNull();
|
|
156
|
+
expect(pkg).not.toBeNull();
|
|
157
|
+
// Defaults select "all".
|
|
158
|
+
expect(kind.value).toBe('');
|
|
159
|
+
expect(pkg.value).toBe('');
|
|
160
|
+
expect(kind.options[0].textContent).toBe('All kinds');
|
|
161
|
+
expect(pkg.options[0].textContent).toBe('All packages');
|
|
162
|
+
// Order in the controls row: Kind, Package, then the search box.
|
|
163
|
+
expect(kind.compareDocumentPosition(pkg) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
164
|
+
expect(pkg.compareDocumentPosition(search) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
165
|
+
});
|
|
166
|
+
it('filters the table by the selected Package', () => {
|
|
167
|
+
const env = loadEnv({
|
|
168
|
+
version: '2.0',
|
|
169
|
+
tool: 'graph',
|
|
170
|
+
language: 'typescript',
|
|
171
|
+
builtAt: 'now',
|
|
172
|
+
functions: {
|
|
173
|
+
a: [
|
|
174
|
+
makeOcc({
|
|
175
|
+
bodyHash: 'a',
|
|
176
|
+
simpleName: 'validateInput',
|
|
177
|
+
filePath: 'packages/cli/src/a.ts',
|
|
178
|
+
}),
|
|
179
|
+
],
|
|
180
|
+
z: [
|
|
181
|
+
makeOcc({
|
|
182
|
+
bodyHash: 'z',
|
|
183
|
+
simpleName: 'ztarget',
|
|
184
|
+
filePath: 'packages/contracts/src/z.ts',
|
|
185
|
+
}),
|
|
186
|
+
],
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
const view = document.createElement('div');
|
|
190
|
+
env.views
|
|
191
|
+
.find((v) => v.id === 'distribution')
|
|
192
|
+
.render(view, env.graphCatalog, env.graphIndexes, env.filterState);
|
|
193
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(2);
|
|
194
|
+
const pkg = view.querySelector('select[data-control="fn-package"]');
|
|
195
|
+
pkg.value = 'contracts';
|
|
196
|
+
pkg.dispatchEvent(new Event('change', { bubbles: true }));
|
|
197
|
+
const rows = view.querySelectorAll('[data-body-hash]');
|
|
198
|
+
expect(rows.length).toBe(1);
|
|
199
|
+
expect(view.textContent).toContain('ztarget');
|
|
200
|
+
expect(view.textContent).not.toContain('validateInput');
|
|
201
|
+
});
|
|
202
|
+
it('no longer renders a "Test-only" column', () => {
|
|
203
|
+
const { view } = renderDistribution();
|
|
204
|
+
const headers = [...view.querySelectorAll('th')].map((th) => th.textContent);
|
|
205
|
+
expect(headers).not.toContain('Test-only');
|
|
206
|
+
});
|
|
207
|
+
it('the "Test-only" toggle narrows the table to test-only functions', () => {
|
|
208
|
+
const edge = {
|
|
209
|
+
line: 1,
|
|
210
|
+
column: 0,
|
|
211
|
+
resolution: 'static',
|
|
212
|
+
confidence: 'high',
|
|
213
|
+
text: 'x()',
|
|
214
|
+
};
|
|
215
|
+
const env = loadEnv({
|
|
216
|
+
version: '2.0',
|
|
217
|
+
tool: 'graph',
|
|
218
|
+
language: 'typescript',
|
|
219
|
+
builtAt: 'now',
|
|
220
|
+
functions: {
|
|
221
|
+
// Production fn reached ONLY from a test file → test-only.
|
|
222
|
+
prod: [
|
|
223
|
+
makeOcc({ bodyHash: 'prod', simpleName: 'prodFn', filePath: 'packages/cli/src/prod.ts' }),
|
|
224
|
+
],
|
|
225
|
+
// Production fn reached from production code → not test-only.
|
|
226
|
+
normal: [
|
|
227
|
+
makeOcc({
|
|
228
|
+
bodyHash: 'normal',
|
|
229
|
+
simpleName: 'normalFn',
|
|
230
|
+
filePath: 'packages/cli/src/normal.ts',
|
|
231
|
+
}),
|
|
232
|
+
],
|
|
233
|
+
normalCaller: [
|
|
234
|
+
makeOcc({
|
|
235
|
+
bodyHash: 'normalCaller',
|
|
236
|
+
simpleName: 'callerFn',
|
|
237
|
+
filePath: 'packages/cli/src/nc.ts',
|
|
238
|
+
calls: [{ to: ['normal'], ...edge }],
|
|
239
|
+
}),
|
|
240
|
+
],
|
|
241
|
+
// A test-file fn that calls prod (excluded from the table by production-only default).
|
|
242
|
+
testFn: [
|
|
243
|
+
makeOcc({
|
|
244
|
+
bodyHash: 'testFn',
|
|
245
|
+
simpleName: 'testFn',
|
|
246
|
+
filePath: 'packages/cli/src/__tests__/t.test.ts',
|
|
247
|
+
inTestFile: true,
|
|
248
|
+
calls: [{ to: ['prod'], ...edge }],
|
|
249
|
+
}),
|
|
250
|
+
],
|
|
251
|
+
},
|
|
252
|
+
});
|
|
253
|
+
const view = document.createElement('div');
|
|
254
|
+
env.views
|
|
255
|
+
.find((v) => v.id === 'distribution')
|
|
256
|
+
.render(view, env.graphCatalog, env.graphIndexes, env.filterState);
|
|
257
|
+
// Production-only by default (testFn lives in a test file) → 3 rows.
|
|
258
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(3);
|
|
259
|
+
const toggle = view.querySelector('input[data-control="fn-toggle"]');
|
|
260
|
+
expect(toggle).not.toBeNull();
|
|
261
|
+
// The toggle renders after the search box.
|
|
262
|
+
const search = view.querySelector('#code-paths-search-distribution');
|
|
263
|
+
expect(search.compareDocumentPosition(toggle) & Node.DOCUMENT_POSITION_FOLLOWING).toBeTruthy();
|
|
264
|
+
toggle.checked = true;
|
|
265
|
+
toggle.dispatchEvent(new Event('change', { bubbles: true }));
|
|
266
|
+
// Only the test-only production function remains.
|
|
267
|
+
expect(view.querySelectorAll('[data-body-hash]').length).toBe(1);
|
|
268
|
+
expect(view.textContent).toContain('prodFn');
|
|
269
|
+
expect(view.textContent).not.toContain('normalFn');
|
|
270
|
+
});
|
|
271
|
+
});
|
|
272
|
+
//# sourceMappingURL=dashboard-view-distribution.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-view-distribution.test.js","sourceRoot":"","sources":["../../src/__tests__/dashboard-view-distribution.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @vitest-environment jsdom
|
|
3
|
+
*
|
|
4
|
+
* View 8 (Visualization) — Cytoscape PACKAGE node-link view (item 10/11).
|
|
5
|
+
*
|
|
6
|
+
* The emitter is snapshotted (matches the other view-*.test.ts pattern) and
|
|
7
|
+
* exercised structurally: the view registers with id 'graph' and label
|
|
8
|
+
* 'Visualization', renders the layout selector + canvas from an embedded
|
|
9
|
+
* package-level view-model blob, falls back to an empty state when the blob is
|
|
10
|
+
* missing, and bans any @opensip-cli/graph import.
|
|
11
|
+
*/
|
|
12
|
+
export {};
|
|
13
|
+
//# sourceMappingURL=dashboard-view-graph.test.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"dashboard-view-graph.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dashboard-view-graph.test.ts"],"names":[],"mappings":"AACA;;;;;;;;;;GAUG"}
|
|
@@ -0,0 +1,332 @@
|
|
|
1
|
+
/// <reference lib="dom" />
|
|
2
|
+
/**
|
|
3
|
+
* @vitest-environment jsdom
|
|
4
|
+
*
|
|
5
|
+
* View 8 (Visualization) — Cytoscape PACKAGE node-link view (item 10/11).
|
|
6
|
+
*
|
|
7
|
+
* The emitter is snapshotted (matches the other view-*.test.ts pattern) and
|
|
8
|
+
* exercised structurally: the view registers with id 'graph' and label
|
|
9
|
+
* 'Visualization', renders the layout selector + canvas from an embedded
|
|
10
|
+
* package-level view-model blob, falls back to an empty state when the blob is
|
|
11
|
+
* missing, and bans any @opensip-cli/graph import.
|
|
12
|
+
*/
|
|
13
|
+
import { describe, expect, it, beforeEach } from 'vitest';
|
|
14
|
+
import { dashboardCytoscapeVendorJs } from '../code-paths/cytoscape-vendor.js';
|
|
15
|
+
import { dashboardFiltersJs } from '../code-paths/filters.js';
|
|
16
|
+
import { dashboardFunctionRowJs } from '../code-paths/function-row.js';
|
|
17
|
+
import { dashboardHelpDrawerJs } from '../code-paths/help-drawer.js';
|
|
18
|
+
import { dashboardIndexesJs } from '../code-paths/indexes.js';
|
|
19
|
+
import { dashboardPathUtilsJs } from '../code-paths/path-utils.js';
|
|
20
|
+
import { dashboardSearchJs } from '../code-paths/search.js';
|
|
21
|
+
import { dashboardViewGraphJs } from '../code-paths/view-graph.js';
|
|
22
|
+
import { dashboardViewsRegistryJs } from '../code-paths/views-registry.js';
|
|
23
|
+
function loadEnv(withVendor) {
|
|
24
|
+
const elSrc = `
|
|
25
|
+
function el(tag, attrs, children) {
|
|
26
|
+
const e = document.createElement(tag);
|
|
27
|
+
if (attrs) Object.entries(attrs).forEach(([k,v]) => {
|
|
28
|
+
if (k === 'text') e.textContent = v;
|
|
29
|
+
else if (k === 'class') e.className = v;
|
|
30
|
+
else if (k.startsWith('on')) e.addEventListener(k.slice(2), v);
|
|
31
|
+
else e.setAttribute(k, v);
|
|
32
|
+
});
|
|
33
|
+
if (children) children.forEach(c => { if (typeof c === 'string') e.appendChild(document.createTextNode(c)); else if (c) e.appendChild(c); });
|
|
34
|
+
return e;
|
|
35
|
+
}
|
|
36
|
+
var graphCatalog = null;
|
|
37
|
+
var graphIndexes = { byBodyHash: new Map(), bySimpleName: new Map(), callees: new Map(), callers: new Map() };
|
|
38
|
+
`;
|
|
39
|
+
const tail = `
|
|
40
|
+
return { views };
|
|
41
|
+
`;
|
|
42
|
+
const parts = [elSrc];
|
|
43
|
+
if (withVendor)
|
|
44
|
+
parts.push(dashboardCytoscapeVendorJs());
|
|
45
|
+
parts.push(dashboardPathUtilsJs(), dashboardIndexesJs(), dashboardViewsRegistryJs(), dashboardFiltersJs(), dashboardSearchJs(), dashboardFunctionRowJs(), // declares makeSectionHeading (the ⓘ heading helper)
|
|
46
|
+
dashboardHelpDrawerJs(), // declares openHelpDrawer (so the ⓘ button renders)
|
|
47
|
+
dashboardViewGraphJs(), tail);
|
|
48
|
+
// eslint-disable-next-line @typescript-eslint/no-implied-eval, sonarjs/code-eval -- Trusted source.
|
|
49
|
+
const factory = new Function(parts.join('\n'));
|
|
50
|
+
return factory();
|
|
51
|
+
}
|
|
52
|
+
function embedViewModel(vm) {
|
|
53
|
+
const blob = document.createElement('script');
|
|
54
|
+
blob.type = 'application/json';
|
|
55
|
+
blob.id = 'graph-view-model';
|
|
56
|
+
blob.textContent = JSON.stringify(vm);
|
|
57
|
+
document.body.append(blob);
|
|
58
|
+
}
|
|
59
|
+
// Package-level sample: two packages, one directed edge pkg-a → pkg-b.
|
|
60
|
+
const SAMPLE_VM = {
|
|
61
|
+
language: 'typescript',
|
|
62
|
+
nodes: [
|
|
63
|
+
{ id: 'pkg-a', label: 'pkg-a', totalCoupling: 3, sccId: null },
|
|
64
|
+
{ id: 'pkg-b', label: 'pkg-b', totalCoupling: 3, sccId: null },
|
|
65
|
+
],
|
|
66
|
+
edges: [{ source: 'pkg-a', target: 'pkg-b', weight: 3, isCycleEdge: false }],
|
|
67
|
+
};
|
|
68
|
+
beforeEach(() => {
|
|
69
|
+
document.body.innerHTML = '';
|
|
70
|
+
});
|
|
71
|
+
describe('dashboardViewGraphJs (emitter)', () => {
|
|
72
|
+
it('matches the snapshot', () => {
|
|
73
|
+
expect(dashboardViewGraphJs()).toMatchSnapshot();
|
|
74
|
+
});
|
|
75
|
+
it('imports nothing from @opensip-cli/graph', () => {
|
|
76
|
+
expect(dashboardViewGraphJs()).not.toContain('@opensip-cli/graph');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
describe('View 8 — Visualization', () => {
|
|
80
|
+
it('registers a view with id "graph" and label "Visualization"', () => {
|
|
81
|
+
const env = loadEnv(false);
|
|
82
|
+
const view = env.views.find((v) => v.id === 'graph');
|
|
83
|
+
expect(view).toBeDefined();
|
|
84
|
+
expect(view.label).toBe('Visualization');
|
|
85
|
+
expect(typeof view.render).toBe('function');
|
|
86
|
+
expect(typeof view.onActivate).toBe('function');
|
|
87
|
+
});
|
|
88
|
+
it('keeps the view id stable as "graph" for deep-link hashes', () => {
|
|
89
|
+
// The label changed (item 11) but the id must NOT churn.
|
|
90
|
+
expect(dashboardViewGraphJs()).toContain("id: 'graph'");
|
|
91
|
+
expect(dashboardViewGraphJs()).toContain("label: 'Visualization'");
|
|
92
|
+
});
|
|
93
|
+
it('renders the empty state when no view-model blob is present', () => {
|
|
94
|
+
const env = loadEnv(false);
|
|
95
|
+
const c = document.createElement('div');
|
|
96
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
97
|
+
expect(c.querySelector('.empty')).not.toBeNull();
|
|
98
|
+
expect(c.querySelector('.empty').textContent).toContain('No graph to display');
|
|
99
|
+
});
|
|
100
|
+
it('renders the renderer-unavailable state when cytoscape is missing', () => {
|
|
101
|
+
const env = loadEnv(false); // no vendor → no cytoscape global
|
|
102
|
+
embedViewModel(SAMPLE_VM);
|
|
103
|
+
const c = document.createElement('div');
|
|
104
|
+
document.body.append(c);
|
|
105
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
106
|
+
expect(c.querySelector('.empty').textContent).toContain('Graph renderer unavailable');
|
|
107
|
+
expect(c.querySelector('#code-paths-graph-canvas')).toBeNull();
|
|
108
|
+
});
|
|
109
|
+
it('renders the layout selector as a dropdown with dagre/cose/breadthfirst', () => {
|
|
110
|
+
const env = loadEnv(true);
|
|
111
|
+
embedViewModel(SAMPLE_VM);
|
|
112
|
+
const c = document.createElement('div');
|
|
113
|
+
document.body.append(c);
|
|
114
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
115
|
+
const layout = c.querySelector('select[data-control="layout"]');
|
|
116
|
+
expect(layout).not.toBeNull();
|
|
117
|
+
expect([...layout.options].map((o) => o.value)).toEqual(['dagre', 'cose', 'breadthfirst']);
|
|
118
|
+
expect(layout.value).toBe('dagre'); // default
|
|
119
|
+
});
|
|
120
|
+
it('renders a section heading with an ⓘ help button (consistent with Coupling/Functions)', () => {
|
|
121
|
+
const env = loadEnv(true);
|
|
122
|
+
embedViewModel(SAMPLE_VM);
|
|
123
|
+
const c = document.createElement('div');
|
|
124
|
+
document.body.append(c);
|
|
125
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
126
|
+
const heading = c.querySelector('h3');
|
|
127
|
+
expect(heading).not.toBeNull();
|
|
128
|
+
expect(heading.textContent).toContain('Visualization');
|
|
129
|
+
const info = c.querySelector('.section-info');
|
|
130
|
+
expect(info).not.toBeNull();
|
|
131
|
+
});
|
|
132
|
+
it('renders the "Highlight cycles" toggle as a checkbox in the control toolbar', () => {
|
|
133
|
+
const env = loadEnv(true);
|
|
134
|
+
embedViewModel(SAMPLE_VM);
|
|
135
|
+
const c = document.createElement('div');
|
|
136
|
+
document.body.append(c);
|
|
137
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
138
|
+
const sccCb = c.querySelector('input[type="checkbox"][data-scc-toggle]');
|
|
139
|
+
expect(sccCb).not.toBeNull();
|
|
140
|
+
const lbl = c.querySelector('.code-paths-graph-checkbox');
|
|
141
|
+
expect(lbl).not.toBeNull();
|
|
142
|
+
expect(lbl.textContent).toContain('Highlight cycles');
|
|
143
|
+
});
|
|
144
|
+
it('mounts a cytoscape canvas when the renderer is present', () => {
|
|
145
|
+
const env = loadEnv(true);
|
|
146
|
+
embedViewModel(SAMPLE_VM);
|
|
147
|
+
const c = document.createElement('div');
|
|
148
|
+
document.body.append(c);
|
|
149
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
150
|
+
expect(c.querySelector('#code-paths-graph-canvas')).not.toBeNull();
|
|
151
|
+
});
|
|
152
|
+
it('renders the package-name search box above the canvas', () => {
|
|
153
|
+
const env = loadEnv(true);
|
|
154
|
+
embedViewModel(SAMPLE_VM);
|
|
155
|
+
const c = document.createElement('div');
|
|
156
|
+
document.body.append(c);
|
|
157
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
158
|
+
const input = c.querySelector('#code-paths-graph-search-input');
|
|
159
|
+
expect(input).not.toBeNull();
|
|
160
|
+
expect(input.getAttribute('placeholder')).toContain('package');
|
|
161
|
+
});
|
|
162
|
+
it('reuses the shared fuzzyMatch index for search (no separate index)', () => {
|
|
163
|
+
expect(dashboardViewGraphJs()).toContain('fuzzyMatch');
|
|
164
|
+
});
|
|
165
|
+
it('sizes nodes by totalCoupling and edges by weight (package encoding)', () => {
|
|
166
|
+
const js = dashboardViewGraphJs();
|
|
167
|
+
expect(js).toContain("ele.data('totalCoupling')");
|
|
168
|
+
expect(js).toContain("ele.data('weight')");
|
|
169
|
+
});
|
|
170
|
+
it('drives impact highlight off live package adjacency and clears on Esc', () => {
|
|
171
|
+
const js = dashboardViewGraphJs();
|
|
172
|
+
// Package-level impact uses the live cytoscape neighborhood, not the
|
|
173
|
+
// function-level graphIndexes adjacency.
|
|
174
|
+
expect(js).toContain("incomers('node')");
|
|
175
|
+
expect(js).toContain("outgoers('node')");
|
|
176
|
+
expect(js).toContain("e.key === 'Escape'");
|
|
177
|
+
});
|
|
178
|
+
it('does not consult the shared Explore filterState (the view owns its controls)', () => {
|
|
179
|
+
const js = dashboardViewGraphJs();
|
|
180
|
+
// The view never calls the shared passesFilter; package level is whole-graph
|
|
181
|
+
// and function level applies its OWN Scope/Kind filter inside the projector.
|
|
182
|
+
expect(js).not.toContain('passesFilter');
|
|
183
|
+
expect(js).not.toContain('No nodes match the active filters');
|
|
184
|
+
});
|
|
185
|
+
it('renders Level/Scope/Package/Kind/Edges, with Package, Kind & Edges disabled (not hidden) at package level', () => {
|
|
186
|
+
const env = loadEnv(true);
|
|
187
|
+
embedViewModel(SAMPLE_VM);
|
|
188
|
+
const c = document.createElement('div');
|
|
189
|
+
document.body.append(c);
|
|
190
|
+
env.views.find((v) => v.id === 'graph').render(c, null, null, null);
|
|
191
|
+
const level = c.querySelector('select[data-control="level"]');
|
|
192
|
+
const scope = c.querySelector('select[data-control="scope"]');
|
|
193
|
+
const pkg = c.querySelector('select[data-control="package"]');
|
|
194
|
+
// Kind is a custom multi-select dropdown (trigger button + checkbox panel),
|
|
195
|
+
// not a native <select multiple>.
|
|
196
|
+
const kind = c.querySelector('button[data-control="kind"]');
|
|
197
|
+
const edges = c.querySelector('select[data-control="granularity"]');
|
|
198
|
+
expect(level).not.toBeNull();
|
|
199
|
+
expect(scope).not.toBeNull();
|
|
200
|
+
expect(level.value).toBe('package'); // default
|
|
201
|
+
expect(kind).not.toBeNull();
|
|
202
|
+
expect(kind.classList.contains('code-paths-graph-ms-trigger')).toBe(true);
|
|
203
|
+
// Edges is now ALWAYS rendered (was hidden until function level).
|
|
204
|
+
expect(edges).not.toBeNull();
|
|
205
|
+
// Package, Kind & Edges only apply at function level → disabled (greyed),
|
|
206
|
+
// not hidden, at package level — consistent across the three.
|
|
207
|
+
expect(pkg.disabled).toBe(true);
|
|
208
|
+
expect(kind.disabled).toBe(true);
|
|
209
|
+
expect(edges.disabled).toBe(true);
|
|
210
|
+
});
|
|
211
|
+
it('Kind multi-select enables at function level and updates the graph on close', () => {
|
|
212
|
+
const occA = {
|
|
213
|
+
bodyHash: 'A',
|
|
214
|
+
simpleName: 'a',
|
|
215
|
+
filePath: 'packages/pkg-a/src/a.ts',
|
|
216
|
+
kind: 'function-declaration',
|
|
217
|
+
inTestFile: false,
|
|
218
|
+
qualifiedName: 'a',
|
|
219
|
+
};
|
|
220
|
+
const occB = {
|
|
221
|
+
bodyHash: 'B',
|
|
222
|
+
simpleName: 'b',
|
|
223
|
+
filePath: 'packages/pkg-a/src/b.ts',
|
|
224
|
+
kind: 'method',
|
|
225
|
+
inTestFile: false,
|
|
226
|
+
qualifiedName: 'b',
|
|
227
|
+
};
|
|
228
|
+
const indexes = {
|
|
229
|
+
byBodyHash: new Map([
|
|
230
|
+
['A', occA],
|
|
231
|
+
['B', occB],
|
|
232
|
+
]),
|
|
233
|
+
occurrencesByHash: new Map([
|
|
234
|
+
['A', [occA]],
|
|
235
|
+
['B', [occB]],
|
|
236
|
+
]),
|
|
237
|
+
bySimpleName: new Map(),
|
|
238
|
+
callees: new Map([['A', ['B']]]),
|
|
239
|
+
callers: new Map([['B', ['A']]]),
|
|
240
|
+
};
|
|
241
|
+
const catalog = {
|
|
242
|
+
version: '2.0',
|
|
243
|
+
tool: 'graph',
|
|
244
|
+
language: 'typescript',
|
|
245
|
+
builtAt: 'now',
|
|
246
|
+
functions: { a: [occA], b: [occB] },
|
|
247
|
+
};
|
|
248
|
+
const env = loadEnv(true);
|
|
249
|
+
const c = document.createElement('div');
|
|
250
|
+
document.body.append(c);
|
|
251
|
+
env.views.find((v) => v.id === 'graph').render(c, catalog, indexes, null);
|
|
252
|
+
// Switch to function level + pick pkg-a so Kind becomes enabled.
|
|
253
|
+
const level = c.querySelector('select[data-control="level"]');
|
|
254
|
+
level.value = 'function';
|
|
255
|
+
level.dispatchEvent(new Event('change'));
|
|
256
|
+
const pkg = c.querySelector('select[data-control="package"]');
|
|
257
|
+
pkg.value = 'pkg-a';
|
|
258
|
+
pkg.dispatchEvent(new Event('change'));
|
|
259
|
+
const kindTrigger = c.querySelector('button[data-control="kind"]');
|
|
260
|
+
expect(kindTrigger.disabled).toBe(false);
|
|
261
|
+
expect(kindTrigger.textContent).toContain('All kinds');
|
|
262
|
+
// Open the popover, check one kind, close → graph re-renders, canvas present.
|
|
263
|
+
kindTrigger.dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
264
|
+
const boxes = c.querySelectorAll('.code-paths-graph-ms-panel input[type="checkbox"]');
|
|
265
|
+
expect(boxes.length).toBeGreaterThan(0);
|
|
266
|
+
boxes[0].checked = true;
|
|
267
|
+
boxes[0].dispatchEvent(new Event('change'));
|
|
268
|
+
// Closing (re-click) applies the selection and re-renders.
|
|
269
|
+
c.querySelector('button[data-control="kind"]').dispatchEvent(new MouseEvent('click', { bubbles: true }));
|
|
270
|
+
expect(c.querySelector('#code-paths-graph-canvas')).not.toBeNull();
|
|
271
|
+
});
|
|
272
|
+
it("projects a single package's function graph at function level (intra-package)", () => {
|
|
273
|
+
// Two functions in pkg-a, a → b. Switching to function level + selecting
|
|
274
|
+
// pkg-a should project them into a Cytoscape canvas (intra-package default).
|
|
275
|
+
const occA = {
|
|
276
|
+
bodyHash: 'A',
|
|
277
|
+
simpleName: 'a',
|
|
278
|
+
filePath: 'packages/pkg-a/src/a.ts',
|
|
279
|
+
kind: 'function-declaration',
|
|
280
|
+
inTestFile: false,
|
|
281
|
+
qualifiedName: 'a',
|
|
282
|
+
};
|
|
283
|
+
const occB = {
|
|
284
|
+
bodyHash: 'B',
|
|
285
|
+
simpleName: 'b',
|
|
286
|
+
filePath: 'packages/pkg-a/src/b.ts',
|
|
287
|
+
kind: 'function-declaration',
|
|
288
|
+
inTestFile: false,
|
|
289
|
+
qualifiedName: 'b',
|
|
290
|
+
};
|
|
291
|
+
const indexes = {
|
|
292
|
+
byBodyHash: new Map([
|
|
293
|
+
['A', occA],
|
|
294
|
+
['B', occB],
|
|
295
|
+
]),
|
|
296
|
+
occurrencesByHash: new Map([
|
|
297
|
+
['A', [occA]],
|
|
298
|
+
['B', [occB]],
|
|
299
|
+
]),
|
|
300
|
+
bySimpleName: new Map(),
|
|
301
|
+
callees: new Map([['A', ['B']]]),
|
|
302
|
+
callers: new Map([['B', ['A']]]),
|
|
303
|
+
};
|
|
304
|
+
const catalog = {
|
|
305
|
+
version: '2.0',
|
|
306
|
+
tool: 'graph',
|
|
307
|
+
language: 'typescript',
|
|
308
|
+
builtAt: 'now',
|
|
309
|
+
functions: { a: [occA], b: [occB] },
|
|
310
|
+
};
|
|
311
|
+
const env = loadEnv(true);
|
|
312
|
+
const c = document.createElement('div');
|
|
313
|
+
document.body.append(c);
|
|
314
|
+
env.views.find((v) => v.id === 'graph').render(c, catalog, indexes, null);
|
|
315
|
+
// Switch Level → function (re-renders in place via the change handler).
|
|
316
|
+
const level = c.querySelector('[data-control="level"]');
|
|
317
|
+
level.value = 'function';
|
|
318
|
+
level.dispatchEvent(new Event('change'));
|
|
319
|
+
// Before a package is chosen, the view prompts for one (no canvas yet).
|
|
320
|
+
expect(c.querySelector('#code-paths-graph-canvas')).toBeNull();
|
|
321
|
+
expect(c.querySelector('.empty').textContent).toContain('Select a package');
|
|
322
|
+
// Choose pkg-a → the function graph projects and the canvas mounts.
|
|
323
|
+
const pkg = c.querySelector('[data-control="package"]');
|
|
324
|
+
expect([...pkg.options].map((o) => o.value)).toContain('pkg-a');
|
|
325
|
+
pkg.value = 'pkg-a';
|
|
326
|
+
pkg.dispatchEvent(new Event('change'));
|
|
327
|
+
expect(c.querySelector('#code-paths-graph-canvas')).not.toBeNull();
|
|
328
|
+
// The Edges (intra vs cross-package) toggle appears only at function level.
|
|
329
|
+
expect(c.querySelector('[data-control="granularity"]')).not.toBeNull();
|
|
330
|
+
});
|
|
331
|
+
});
|
|
332
|
+
//# sourceMappingURL=dashboard-view-graph.test.js.map
|