@opensip-cli/dashboard 0.1.7 → 0.1.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/__tests__/catalog-provenance.test.js +6 -24
- package/dist/__tests__/catalog-provenance.test.js.map +1 -1
- package/dist/__tests__/coupling-attribution.test.js +10 -14
- package/dist/__tests__/coupling-attribution.test.js.map +1 -1
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts +9 -2
- package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-bundle-weight.test.js +19 -12
- package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -1
- package/dist/__tests__/dashboard-cell-containment.test.js +5 -2
- package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -1
- package/dist/__tests__/dashboard-editor-link.test.d.ts +9 -0
- package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-editor-link.test.js +72 -21
- package/dist/__tests__/dashboard-editor-link.test.js.map +1 -1
- package/dist/__tests__/dashboard-el.test.d.ts +18 -0
- package/dist/__tests__/dashboard-el.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-el.test.js +90 -0
- package/dist/__tests__/dashboard-el.test.js.map +1 -0
- package/dist/__tests__/dashboard-filters.test.js +6 -14
- package/dist/__tests__/dashboard-filters.test.js.map +1 -1
- package/dist/__tests__/dashboard-function-card-singleton.test.js +15 -27
- package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -1
- package/dist/__tests__/dashboard-function-card.test.d.ts +4 -4
- package/dist/__tests__/dashboard-function-card.test.js +80 -44
- package/dist/__tests__/dashboard-function-card.test.js.map +1 -1
- package/dist/__tests__/dashboard-function-row.test.js +52 -51
- package/dist/__tests__/dashboard-function-row.test.js.map +1 -1
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js +3 -1
- package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -1
- package/dist/__tests__/dashboard-graph-offline.integration.test.js +3 -1
- package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -1
- package/dist/__tests__/dashboard-help-drawer.test.js +11 -17
- package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -1
- package/dist/__tests__/dashboard-indexes.test.d.ts +6 -4
- package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-indexes.test.js +10 -7
- package/dist/__tests__/dashboard-indexes.test.js.map +1 -1
- package/dist/__tests__/dashboard-pagination.test.d.ts +15 -0
- package/dist/__tests__/dashboard-pagination.test.d.ts.map +1 -0
- package/dist/__tests__/dashboard-pagination.test.js +140 -0
- package/dist/__tests__/dashboard-pagination.test.js.map +1 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts +7 -0
- package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-path-utils.test.js +11 -3
- package/dist/__tests__/dashboard-path-utils.test.js.map +1 -1
- package/dist/__tests__/dashboard-search.test.d.ts +5 -0
- package/dist/__tests__/dashboard-search.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-search.test.js +9 -3
- package/dist/__tests__/dashboard-search.test.js.map +1 -1
- package/dist/__tests__/dashboard-sessions.test.js +13 -11
- package/dist/__tests__/dashboard-sessions.test.js.map +1 -1
- package/dist/__tests__/dashboard-trace.test.d.ts +11 -0
- package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-trace.test.js +55 -32
- package/dist/__tests__/dashboard-trace.test.js.map +1 -1
- package/dist/__tests__/dashboard-view-conformance.test.js +9 -15
- package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -1
- package/dist/__tests__/dashboard-view-coupling.test.js +14 -35
- package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -1
- package/dist/__tests__/dashboard-view-distribution.test.js +14 -37
- package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -1
- package/dist/__tests__/dashboard-view-graph.test.js +29 -62
- package/dist/__tests__/dashboard-view-graph.test.js.map +1 -1
- package/dist/__tests__/dashboard-view-template.test.d.ts +13 -14
- package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -1
- package/dist/__tests__/dashboard-view-template.test.js +165 -112
- package/dist/__tests__/dashboard-view-template.test.js.map +1 -1
- package/dist/__tests__/graph-tab.test.js +4 -2
- package/dist/__tests__/graph-tab.test.js.map +1 -1
- package/dist/client/el.d.ts +17 -0
- package/dist/client/el.d.ts.map +1 -0
- package/dist/client/el.js +36 -0
- package/dist/client/el.js.map +1 -0
- package/dist/client-bundle.generated.d.ts +2 -0
- package/dist/client-bundle.generated.d.ts.map +1 -0
- package/dist/client-bundle.generated.js +3 -0
- package/dist/client-bundle.generated.js.map +1 -0
- package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -8
- package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -1
- package/dist/code-paths/__tests__/views-registry.test.js +27 -25
- package/dist/code-paths/__tests__/views-registry.test.js.map +1 -1
- package/dist/code-paths.d.ts +21 -62
- package/dist/code-paths.d.ts.map +1 -1
- package/dist/code-paths.js +24 -349
- package/dist/code-paths.js.map +1 -1
- package/dist/generator.d.ts +2 -0
- package/dist/generator.d.ts.map +1 -1
- package/dist/generator.js +28 -17
- package/dist/generator.js.map +1 -1
- package/package.json +5 -4
- package/dist/checks.d.ts +0 -7
- package/dist/checks.d.ts.map +0 -1
- package/dist/checks.js +0 -283
- package/dist/checks.js.map +0 -1
- package/dist/code-paths/catalog-provenance.d.ts +0 -22
- package/dist/code-paths/catalog-provenance.d.ts.map +0 -1
- package/dist/code-paths/catalog-provenance.js +0 -108
- package/dist/code-paths/catalog-provenance.js.map +0 -1
- package/dist/code-paths/catalog-recipes-tables.d.ts +0 -11
- package/dist/code-paths/catalog-recipes-tables.d.ts.map +0 -1
- package/dist/code-paths/catalog-recipes-tables.js +0 -86
- package/dist/code-paths/catalog-recipes-tables.js.map +0 -1
- package/dist/code-paths/editor-link.d.ts +0 -10
- package/dist/code-paths/editor-link.d.ts.map +0 -1
- package/dist/code-paths/editor-link.js +0 -20
- package/dist/code-paths/editor-link.js.map +0 -1
- package/dist/code-paths/filters.d.ts +0 -19
- package/dist/code-paths/filters.d.ts.map +0 -1
- package/dist/code-paths/filters.js +0 -47
- package/dist/code-paths/filters.js.map +0 -1
- package/dist/code-paths/function-card.d.ts +0 -15
- package/dist/code-paths/function-card.d.ts.map +0 -1
- package/dist/code-paths/function-card.js +0 -169
- package/dist/code-paths/function-card.js.map +0 -1
- package/dist/code-paths/function-row.d.ts +0 -17
- package/dist/code-paths/function-row.d.ts.map +0 -1
- package/dist/code-paths/function-row.js +0 -77
- package/dist/code-paths/function-row.js.map +0 -1
- package/dist/code-paths/graph-controls.d.ts +0 -27
- package/dist/code-paths/graph-controls.d.ts.map +0 -1
- package/dist/code-paths/graph-controls.js +0 -257
- package/dist/code-paths/graph-controls.js.map +0 -1
- package/dist/code-paths/graph-stylesheet.d.ts +0 -22
- package/dist/code-paths/graph-stylesheet.d.ts.map +0 -1
- package/dist/code-paths/graph-stylesheet.js +0 -121
- package/dist/code-paths/graph-stylesheet.js.map +0 -1
- package/dist/code-paths/help-drawer.d.ts +0 -18
- package/dist/code-paths/help-drawer.d.ts.map +0 -1
- package/dist/code-paths/help-drawer.js +0 -54
- package/dist/code-paths/help-drawer.js.map +0 -1
- package/dist/code-paths/indexes.d.ts +0 -28
- package/dist/code-paths/indexes.d.ts.map +0 -1
- package/dist/code-paths/indexes.js +0 -97
- package/dist/code-paths/indexes.js.map +0 -1
- package/dist/code-paths/path-utils.d.ts +0 -15
- package/dist/code-paths/path-utils.d.ts.map +0 -1
- package/dist/code-paths/path-utils.js +0 -47
- package/dist/code-paths/path-utils.js.map +0 -1
- package/dist/code-paths/search.d.ts +0 -14
- package/dist/code-paths/search.d.ts.map +0 -1
- package/dist/code-paths/search.js +0 -54
- package/dist/code-paths/search.js.map +0 -1
- package/dist/code-paths/trace.d.ts +0 -11
- package/dist/code-paths/trace.d.ts.map +0 -1
- package/dist/code-paths/trace.js +0 -60
- package/dist/code-paths/trace.js.map +0 -1
- package/dist/code-paths/view-coupling.d.ts +0 -22
- package/dist/code-paths/view-coupling.d.ts.map +0 -1
- package/dist/code-paths/view-coupling.js +0 -218
- package/dist/code-paths/view-coupling.js.map +0 -1
- package/dist/code-paths/view-distribution.d.ts +0 -20
- package/dist/code-paths/view-distribution.d.ts.map +0 -1
- package/dist/code-paths/view-distribution.js +0 -82
- package/dist/code-paths/view-distribution.js.map +0 -1
- package/dist/code-paths/view-graph.d.ts +0 -35
- package/dist/code-paths/view-graph.d.ts.map +0 -1
- package/dist/code-paths/view-graph.js +0 -379
- package/dist/code-paths/view-graph.js.map +0 -1
- package/dist/code-paths/view-template.d.ts +0 -154
- package/dist/code-paths/view-template.d.ts.map +0 -1
- package/dist/code-paths/view-template.js +0 -218
- package/dist/code-paths/view-template.js.map +0 -1
- package/dist/code-paths/views-registry.d.ts +0 -13
- package/dist/code-paths/views-registry.d.ts.map +0 -1
- package/dist/code-paths/views-registry.js +0 -53
- package/dist/code-paths/views-registry.js.map +0 -1
- package/dist/overview.d.ts +0 -13
- package/dist/overview.d.ts.map +0 -1
- package/dist/overview.js +0 -91
- package/dist/overview.js.map +0 -1
- package/dist/recipes.d.ts +0 -6
- package/dist/recipes.d.ts.map +0 -1
- package/dist/recipes.js +0 -68
- package/dist/recipes.js.map +0 -1
- package/dist/sessions.d.ts +0 -6
- package/dist/sessions.d.ts.map +0 -1
- package/dist/sessions.js +0 -288
- package/dist/sessions.js.map +0 -1
- package/dist/shared/el.d.ts +0 -13
- package/dist/shared/el.d.ts.map +0 -1
- package/dist/shared/el.js +0 -27
- package/dist/shared/el.js.map +0 -1
- package/dist/shared/pagination.d.ts +0 -15
- package/dist/shared/pagination.d.ts.map +0 -1
- package/dist/shared/pagination.js +0 -113
- package/dist/shared/pagination.js.map +0 -1
- package/dist/shared/sortable.d.ts +0 -14
- package/dist/shared/sortable.d.ts.map +0 -1
- package/dist/shared/sortable.js +0 -101
- package/dist/shared/sortable.js.map +0 -1
- package/dist/shared/tab-activators.d.ts +0 -16
- package/dist/shared/tab-activators.d.ts.map +0 -1
- package/dist/shared/tab-activators.js +0 -33
- package/dist/shared/tab-activators.js.map +0 -1
- package/dist/shared/tab-bar.d.ts +0 -8
- package/dist/shared/tab-bar.d.ts.map +0 -1
- package/dist/shared/tab-bar.js +0 -20
- package/dist/shared/tab-bar.js.map +0 -1
- package/dist/shared.d.ts +0 -26
- package/dist/shared.d.ts.map +0 -1
- package/dist/shared.js +0 -39
- package/dist/shared.js.map +0 -1
- package/dist/subtab-bar.d.ts +0 -23
- package/dist/subtab-bar.d.ts.map +0 -1
- package/dist/subtab-bar.js +0 -77
- package/dist/subtab-bar.js.map +0 -1
- package/dist/tool-tabs.d.ts +0 -12
- package/dist/tool-tabs.d.ts.map +0 -1
- package/dist/tool-tabs.js +0 -80
- package/dist/tool-tabs.js.map +0 -1
package/dist/sessions.js
DELETED
|
@@ -1,288 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Session table + session detail rendering — used by fitness/sim tabs.
|
|
3
|
-
* Returns JS code as a string.
|
|
4
|
-
*/
|
|
5
|
-
export function dashboardSessionsJs() {
|
|
6
|
-
return String.raw `
|
|
7
|
-
// =======================================================
|
|
8
|
-
// SESSION TABLE (used by fitness/sim tabs)
|
|
9
|
-
// =======================================================
|
|
10
|
-
|
|
11
|
-
// Per-rule metric column map for the expanded findings table. For these
|
|
12
|
-
// graph rules the finding message just repeats the file + the metric, so
|
|
13
|
-
// we DROP the Message column and render a dedicated metric column read
|
|
14
|
-
// from finding.metadata (persisted on the signal metadata payload).
|
|
15
|
-
const RULE_METRIC_COLUMNS = {
|
|
16
|
-
'graph:large-function': { label: 'Lines', key: 'bodyLines' },
|
|
17
|
-
'graph:high-blast-untested': { label: 'Score', key: 'blast' },
|
|
18
|
-
'graph:wide-function': { label: 'Parameters', key: 'paramCount' },
|
|
19
|
-
'graph:cycle': { label: 'Call Cycle', key: 'sccSize' },
|
|
20
|
-
};
|
|
21
|
-
|
|
22
|
-
/** Derive 3-state session status: 'fail' | 'warn' | 'pass'
|
|
23
|
-
* Counts live in the tool-owned opaque payload (summary). */
|
|
24
|
-
function sessionStatus(s) {
|
|
25
|
-
const sm = (s.payload && s.payload.summary) || {};
|
|
26
|
-
if (sm.failed > 0) return 'fail';
|
|
27
|
-
if (sm.warnings > 0) return 'warn';
|
|
28
|
-
return 'pass';
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
function statusBadge(status) {
|
|
32
|
-
const labels = { fail: 'FAIL', warn: 'WARN', pass: 'PASS' };
|
|
33
|
-
const classes = { fail: 'badge-fail', warn: 'badge-warn', pass: 'badge-pass' };
|
|
34
|
-
return el('span', {class:'badge ' + classes[status], text: labels[status]});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
function renderSessionTable(panel, toolSessions, accentColor) {
|
|
38
|
-
if (!toolSessions.length) {
|
|
39
|
-
panel.appendChild(el('div', {class:'empty', text:'No sessions yet.'}));
|
|
40
|
-
return;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
const tool = toolSessions[0].tool;
|
|
44
|
-
|
|
45
|
-
const table = el('table', {class:'data-table sortable'});
|
|
46
|
-
const thead = el('thead');
|
|
47
|
-
const headerRow = el('tr');
|
|
48
|
-
['Timestamp', 'Recipe', 'Pass Rate', 'Status', 'Passed', 'Failed', 'Findings', 'Duration'].forEach(h => {
|
|
49
|
-
headerRow.appendChild(el('th', {text: h}));
|
|
50
|
-
});
|
|
51
|
-
thead.appendChild(headerRow);
|
|
52
|
-
table.appendChild(thead);
|
|
53
|
-
|
|
54
|
-
const tbody = el('tbody');
|
|
55
|
-
toolSessions.forEach((s, idx) => {
|
|
56
|
-
const sc = s.score >= 90 ? 'color:var(--success)' : s.score >= 70 ? 'color:var(--warning)' : 'color:var(--error)';
|
|
57
|
-
const sm = (s.payload && s.payload.summary) || { total: 0, passed: 0, failed: 0, errors: 0, warnings: 0 };
|
|
58
|
-
const row = el('tr', {class:'clickable', id: 'session-row-' + tool + '-' + idx, 'data-session-id': s.id, onclick: () => {
|
|
59
|
-
tbody.querySelectorAll('tr.selected').forEach(r => r.classList.remove('selected'));
|
|
60
|
-
row.classList.add('selected');
|
|
61
|
-
renderDetail(s, idx);
|
|
62
|
-
}});
|
|
63
|
-
row.appendChild(el('td', {class:'cell-nowrap', text: new Date(s.startedAt).toLocaleString()}));
|
|
64
|
-
row.appendChild(el('td', {text: s.recipe || 'default', style:'color:var(--text-muted)'}));
|
|
65
|
-
const scoreCell = el('td', {style: 'font-weight:600;' + sc});
|
|
66
|
-
scoreCell.textContent = s.score + '%';
|
|
67
|
-
row.appendChild(scoreCell);
|
|
68
|
-
const badgeCell = el('td');
|
|
69
|
-
badgeCell.appendChild(statusBadge(sessionStatus(s)));
|
|
70
|
-
row.appendChild(badgeCell);
|
|
71
|
-
row.appendChild(el('td', {text: ''+sm.passed, style:'color:var(--success)'}));
|
|
72
|
-
row.appendChild(el('td', {text: ''+sm.failed, style: sm.failed > 0 ? 'color:var(--error)' : 'color:var(--text-dim)'}));
|
|
73
|
-
row.appendChild(el('td', {text: ''+(sm.errors + (sm.warnings || 0))}));
|
|
74
|
-
row.appendChild(el('td', {text: (s.durationMs/1000).toFixed(1)+'s', style:'color:var(--text-dim)'}));
|
|
75
|
-
tbody.appendChild(row);
|
|
76
|
-
});
|
|
77
|
-
table.appendChild(tbody);
|
|
78
|
-
|
|
79
|
-
const sessionPag = el('div', {class:'pagination'});
|
|
80
|
-
const sec = el('div', {class:'section'}, [el('h3', {text:'Sessions (' + toolSessions.length + ')'}), el('div', {class:'card'}, [table, sessionPag])]);
|
|
81
|
-
panel.appendChild(sec);
|
|
82
|
-
paginateTable(tbody, sessionPag, 10);
|
|
83
|
-
|
|
84
|
-
// Detail container — kept as a direct reference, no global ID lookup needed
|
|
85
|
-
const detailContainer = el('div', {id: 'detail-' + tool + '-' + Math.random().toString(36).slice(2,8), class:'section', style:'display:none'});
|
|
86
|
-
panel.appendChild(detailContainer);
|
|
87
|
-
|
|
88
|
-
function renderDetail(session, idx) {
|
|
89
|
-
detailContainer.style.display = 'block';
|
|
90
|
-
while (detailContainer.firstChild) detailContainer.removeChild(detailContainer.firstChild);
|
|
91
|
-
|
|
92
|
-
// Sessions written before the tool-owned payload split (or by a tool
|
|
93
|
-
// that records no per-item detail) have no payload at all. Distinguish
|
|
94
|
-
// that from "payload present but empty" so the panel says so explicitly
|
|
95
|
-
// rather than rendering a silent empty table.
|
|
96
|
-
if (!session.payload) {
|
|
97
|
-
detailContainer.appendChild(el('h3', {text: 'Session Detail — ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
|
|
98
|
-
detailContainer.appendChild(el('div', {class:'empty', text:'No detail recorded for this session.'}));
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
|
|
102
|
-
// Per-item detail lives in the tool-owned opaque payload. Fitness calls
|
|
103
|
-
// these "checks"; graph groups signals by rule (relabeled below).
|
|
104
|
-
const checks = (session.payload && session.payload.checks) || [];
|
|
105
|
-
|
|
106
|
-
// A payload that records no per-item rows (e.g. a clean graph run — graph
|
|
107
|
-
// only persists rules that emitted a finding) would otherwise render a
|
|
108
|
-
// header-only table that reads as "nothing shows up". Render an explicit
|
|
109
|
-
// empty state instead so a clean run is unambiguous.
|
|
110
|
-
if (checks.length === 0) {
|
|
111
|
-
detailContainer.appendChild(el('h3', {text: 'Session Detail — ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
|
|
112
|
-
const sm = (session.payload && session.payload.summary) || {};
|
|
113
|
-
const clean = !((sm.errors || 0) > 0 || (sm.warnings || 0) > 0);
|
|
114
|
-
const subline = el('div', {style:'color:var(--text-dim);font-size:12px;margin-bottom:12px'});
|
|
115
|
-
subline.textContent = session.cwd + (session.recipe ? ' — recipe: ' + session.recipe : '');
|
|
116
|
-
detailContainer.appendChild(subline);
|
|
117
|
-
detailContainer.appendChild(el('div', {class:'empty', text: clean
|
|
118
|
-
? 'No findings — this run was clean. Every rule passed with zero violations.'
|
|
119
|
-
: 'No per-rule detail was recorded for this run.'}));
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
// Compute session-level totals from check findings
|
|
124
|
-
let totalErrors = 0;
|
|
125
|
-
let totalWarnings = 0;
|
|
126
|
-
checks.forEach(c => {
|
|
127
|
-
if (c.findings) {
|
|
128
|
-
c.findings.forEach(f => {
|
|
129
|
-
if (f.severity === 'error') totalErrors++;
|
|
130
|
-
else if (f.severity === 'warning') totalWarnings++;
|
|
131
|
-
});
|
|
132
|
-
}
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
const headerRow = el('div', {style:'display:flex;align-items:center;justify-content:space-between;margin-bottom:16px'});
|
|
136
|
-
const headerLeft = el('div');
|
|
137
|
-
headerLeft.appendChild(el('h3', {text: 'Session Detail \u2014 ' + new Date(session.startedAt).toLocaleString(), style:'margin-bottom:4px'}));
|
|
138
|
-
const sub = el('div', {style:'color:var(--text-dim);font-size:12px'});
|
|
139
|
-
const countParts = [];
|
|
140
|
-
if (totalErrors > 0) countParts.push(totalErrors + ' error' + (totalErrors !== 1 ? 's' : ''));
|
|
141
|
-
if (totalWarnings > 0) countParts.push(totalWarnings + ' warning' + (totalWarnings !== 1 ? 's' : ''));
|
|
142
|
-
const countsStr = countParts.length > 0 ? ' \u2014 ' + countParts.join(', ') : '';
|
|
143
|
-
sub.textContent = session.cwd + (session.recipe ? ' \u2014 recipe: ' + session.recipe : '') + countsStr;
|
|
144
|
-
headerLeft.appendChild(sub);
|
|
145
|
-
headerRow.appendChild(headerLeft);
|
|
146
|
-
|
|
147
|
-
detailContainer.appendChild(headerRow);
|
|
148
|
-
const filterUid = 'df-' + tool + '-' + idx + '-' + Math.random().toString(36).slice(2,6);
|
|
149
|
-
|
|
150
|
-
// Check detail table
|
|
151
|
-
const table = el('table', {class:'data-table sortable'});
|
|
152
|
-
const thead = el('thead');
|
|
153
|
-
const thRow = el('tr');
|
|
154
|
-
// Graph groups findings by rule, not by check — relabel that one
|
|
155
|
-
// column so the header reads in the tool's own vocabulary. The
|
|
156
|
-
// structural payload shape is identical; only the label differs.
|
|
157
|
-
const itemColumn = tool === 'graph' ? 'Rule' : 'Check';
|
|
158
|
-
// Graph rules are dataset queries, not timed units — their per-rule
|
|
159
|
-
// duration is always 0ms, so drop the Duration column for graph
|
|
160
|
-
// sessions. Fitness/sim checks ARE timed; keep it for them.
|
|
161
|
-
const showDuration = tool !== 'graph';
|
|
162
|
-
const itemHeaders = ['', itemColumn, 'Status', 'Errors', 'Warnings', 'Findings'];
|
|
163
|
-
if (showDuration) itemHeaders.push('Duration');
|
|
164
|
-
itemHeaders.forEach(h => {
|
|
165
|
-
thRow.appendChild(el('th', {text: h}));
|
|
166
|
-
});
|
|
167
|
-
thead.appendChild(thRow);
|
|
168
|
-
table.appendChild(thead);
|
|
169
|
-
|
|
170
|
-
const tbody = el('tbody');
|
|
171
|
-
// Sort rules/checks by severity weight: most errors first, then by
|
|
172
|
-
// warning count as a tiebreak (error-then-warning, stable).
|
|
173
|
-
const sortedChecks = [...checks].sort((a, b) => {
|
|
174
|
-
const aErrors = a.findings ? a.findings.filter(f => f.severity === 'error').length : 0;
|
|
175
|
-
const bErrors = b.findings ? b.findings.filter(f => f.severity === 'error').length : 0;
|
|
176
|
-
if (bErrors !== aErrors) return bErrors - aErrors;
|
|
177
|
-
const aWarn = a.findings ? a.findings.filter(f => f.severity === 'warning').length : 0;
|
|
178
|
-
const bWarn = b.findings ? b.findings.filter(f => f.severity === 'warning').length : 0;
|
|
179
|
-
return bWarn - aWarn;
|
|
180
|
-
});
|
|
181
|
-
sortedChecks.forEach((check, i) => {
|
|
182
|
-
const checkErrors = check.findings ? check.findings.filter(f => f.severity === 'error').length : 0;
|
|
183
|
-
const checkWarnings = check.findings ? check.findings.filter(f => f.severity === 'warning').length : 0;
|
|
184
|
-
const findingsTotal = checkErrors + checkWarnings;
|
|
185
|
-
const hasFindings = findingsTotal > 0;
|
|
186
|
-
const expanderId = filterUid + '-exp-' + i;
|
|
187
|
-
const checkStatusVal = check.passed ? 'pass' : 'fail';
|
|
188
|
-
|
|
189
|
-
const arrowCell = el('td', {style:'width:24px;text-align:center;color:var(--text-dim);font-size:12px'});
|
|
190
|
-
if (hasFindings) arrowCell.textContent = '\u25B6';
|
|
191
|
-
|
|
192
|
-
const row = el('tr', {class: hasFindings ? 'clickable' : '', 'data-check-status': checkStatusVal, onclick: hasFindings ? () => {
|
|
193
|
-
const exp = document.getElementById(expanderId);
|
|
194
|
-
if (exp) {
|
|
195
|
-
const isOpen = exp.classList.toggle('open');
|
|
196
|
-
exp.style.display = isOpen ? 'table-row' : 'none';
|
|
197
|
-
arrowCell.textContent = isOpen ? '\u25BC' : '\u25B6';
|
|
198
|
-
}
|
|
199
|
-
row.classList.toggle('expanded');
|
|
200
|
-
} : undefined});
|
|
201
|
-
row.appendChild(arrowCell);
|
|
202
|
-
row.appendChild(el('td', {text: check.checkSlug, style:'font-weight:500'}));
|
|
203
|
-
|
|
204
|
-
const statusCell = el('td');
|
|
205
|
-
statusCell.appendChild(el('span', {class:'badge ' + (check.passed ? 'badge-pass' : 'badge-fail'), text: check.passed ? 'PASS' : 'FAIL'}));
|
|
206
|
-
row.appendChild(statusCell);
|
|
207
|
-
row.appendChild(el('td', {text: ''+checkErrors, style: checkErrors > 0 ? 'color:var(--error)' : 'color:var(--text-dim)'}));
|
|
208
|
-
row.appendChild(el('td', {text: ''+checkWarnings, style: checkWarnings > 0 ? 'color:var(--warning)' : 'color:var(--text-dim)'}));
|
|
209
|
-
row.appendChild(el('td', {text: ''+findingsTotal, style: findingsTotal > 0 ? 'color:var(--text)' : 'color:var(--text-dim)'}));
|
|
210
|
-
if (showDuration) row.appendChild(el('td', {text: check.durationMs > 0 ? check.durationMs + 'ms' : '0ms', style:'color:var(--text-dim)'}));
|
|
211
|
-
tbody.appendChild(row);
|
|
212
|
-
|
|
213
|
-
if (hasFindings) {
|
|
214
|
-
const expRow = el('tr', {id: expanderId, class:'expander-row', 'data-check-status': checkStatusVal});
|
|
215
|
-
const expCell = el('td', {colspan: '' + itemHeaders.length, style:'padding:0'});
|
|
216
|
-
const expContent = el('div', {class:'expander-content'});
|
|
217
|
-
|
|
218
|
-
const fTable = el('table', {class:'data-table', style:'margin:0;border:none'});
|
|
219
|
-
const fHead = el('thead');
|
|
220
|
-
const fHeaderRow = el('tr');
|
|
221
|
-
// Per-rule column shape. Most rules render the default
|
|
222
|
-
// [Severity, Message, File, Suggestion]. The graph metric rules
|
|
223
|
-
// below repeat the file + metric in their message, so they DROP
|
|
224
|
-
// Message and ADD a metric column read from finding.metadata.
|
|
225
|
-
const metricColumn = RULE_METRIC_COLUMNS[check.checkSlug];
|
|
226
|
-
const fHeaders = metricColumn
|
|
227
|
-
? ['Severity', 'File', metricColumn.label, 'Suggestion']
|
|
228
|
-
: ['Severity', 'Message', 'File', 'Suggestion'];
|
|
229
|
-
fHeaders.forEach(h => {
|
|
230
|
-
fHeaderRow.appendChild(el('th', {text: h, style:'font-size:11px;padding:6px 12px'}));
|
|
231
|
-
});
|
|
232
|
-
fHead.appendChild(fHeaderRow);
|
|
233
|
-
fTable.appendChild(fHead);
|
|
234
|
-
|
|
235
|
-
const fBody = el('tbody');
|
|
236
|
-
// Sort findings within the rule: errors first, then warnings (stable).
|
|
237
|
-
const sevWeight = { error: 0, warning: 1 };
|
|
238
|
-
const sortedFindings = [...check.findings].sort((a, b) =>
|
|
239
|
-
(sevWeight[a.severity] ?? 2) - (sevWeight[b.severity] ?? 2));
|
|
240
|
-
sortedFindings.forEach(f => {
|
|
241
|
-
const fRow = el('tr');
|
|
242
|
-
const sevCell = el('td', {style:'padding:6px 12px'});
|
|
243
|
-
sevCell.appendChild(el('span', {class:'finding-sev ' + f.severity, text: f.severity}));
|
|
244
|
-
fRow.appendChild(sevCell);
|
|
245
|
-
const fileText = f.filePath ? f.filePath + (f.line ? ':' + f.line : '') : '\u2014';
|
|
246
|
-
if (metricColumn) {
|
|
247
|
-
fRow.appendChild(el('td', {text: fileText, style:'padding:6px 12px;color:var(--text-dim);font-size:12px'}));
|
|
248
|
-
const mv = f.metadata ? f.metadata[metricColumn.key] : undefined;
|
|
249
|
-
fRow.appendChild(el('td', {text: (mv === undefined || mv === null) ? '\u2014' : '' + mv, style:'padding:6px 12px;font-size:13px'}));
|
|
250
|
-
} else {
|
|
251
|
-
fRow.appendChild(el('td', {text: f.message, style:'padding:6px 12px;font-size:13px'}));
|
|
252
|
-
fRow.appendChild(el('td', {text: fileText, style:'padding:6px 12px;color:var(--text-dim);font-size:12px'}));
|
|
253
|
-
}
|
|
254
|
-
fRow.appendChild(el('td', {text: f.suggestion || '\u2014', style:'padding:6px 12px;color:var(--accent);font-size:12px'}));
|
|
255
|
-
fBody.appendChild(fRow);
|
|
256
|
-
});
|
|
257
|
-
fTable.appendChild(fBody);
|
|
258
|
-
// Wrap the wide findings table in a horizontal-scroll container so
|
|
259
|
-
// long file paths / messages scroll inside the card instead of
|
|
260
|
-
// overrunning the section (mirrors the .coupling-scroll fix).
|
|
261
|
-
const fScroll = el('div', {style:'overflow-x:auto;max-width:100%'}, [fTable]);
|
|
262
|
-
expContent.appendChild(fScroll);
|
|
263
|
-
expCell.appendChild(expContent);
|
|
264
|
-
expRow.appendChild(expCell);
|
|
265
|
-
tbody.appendChild(expRow);
|
|
266
|
-
}
|
|
267
|
-
});
|
|
268
|
-
table.appendChild(tbody);
|
|
269
|
-
const detailPag = el('div', {class:'pagination'});
|
|
270
|
-
detailContainer.appendChild(el('div', {class:'card'}, [table, detailPag]));
|
|
271
|
-
|
|
272
|
-
// Enable sorting on the detail table
|
|
273
|
-
makeSortable(table);
|
|
274
|
-
|
|
275
|
-
// Paginate
|
|
276
|
-
paginateGroupedRows(tbody, detailPag, 10);
|
|
277
|
-
}
|
|
278
|
-
|
|
279
|
-
// Auto-show latest and highlight first row
|
|
280
|
-
renderDetail(toolSessions[0], 0);
|
|
281
|
-
const firstRow = tbody.querySelector('tr');
|
|
282
|
-
if (firstRow) firstRow.classList.add('selected');
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
`;
|
|
287
|
-
}
|
|
288
|
-
//# sourceMappingURL=sessions.js.map
|
package/dist/sessions.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sessions.js","sourceRoot":"","sources":["../src/sessions.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwRlB,CAAC;AACF,CAAC"}
|
package/dist/shared/el.d.ts
DELETED
|
@@ -1,13 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `el(tag, attrs, children)` — tiny DOM-builder helper used everywhere
|
|
3
|
-
* a string of `document.createElement` + setAttribute calls would
|
|
4
|
-
* otherwise live.
|
|
5
|
-
*
|
|
6
|
-
* Special attribute keys: `text` sets `textContent`, `class` sets
|
|
7
|
-
* `className`, anything starting with `on` is treated as an event
|
|
8
|
-
* listener (e.g. `onclick`), everything else passes through to
|
|
9
|
-
* `setAttribute`. `children` may include strings (auto-wrapped into
|
|
10
|
-
* text nodes) or `null`/`undefined` (skipped).
|
|
11
|
-
*/
|
|
12
|
-
export declare function dashboardElJs(): string;
|
|
13
|
-
//# sourceMappingURL=el.d.ts.map
|
package/dist/shared/el.d.ts.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"el.d.ts","sourceRoot":"","sources":["../../src/shared/el.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,wBAAgB,aAAa,IAAI,MAAM,CActC"}
|
package/dist/shared/el.js
DELETED
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* `el(tag, attrs, children)` — tiny DOM-builder helper used everywhere
|
|
3
|
-
* a string of `document.createElement` + setAttribute calls would
|
|
4
|
-
* otherwise live.
|
|
5
|
-
*
|
|
6
|
-
* Special attribute keys: `text` sets `textContent`, `class` sets
|
|
7
|
-
* `className`, anything starting with `on` is treated as an event
|
|
8
|
-
* listener (e.g. `onclick`), everything else passes through to
|
|
9
|
-
* `setAttribute`. `children` may include strings (auto-wrapped into
|
|
10
|
-
* text nodes) or `null`/`undefined` (skipped).
|
|
11
|
-
*/
|
|
12
|
-
export function dashboardElJs() {
|
|
13
|
-
return String.raw `
|
|
14
|
-
function el(tag, attrs, children) {
|
|
15
|
-
const e = document.createElement(tag);
|
|
16
|
-
if (attrs) Object.entries(attrs).forEach(([k,v]) => {
|
|
17
|
-
if (k === 'text') e.textContent = v;
|
|
18
|
-
else if (k === 'class') e.className = v;
|
|
19
|
-
else if (k.startsWith('on')) e.addEventListener(k.slice(2), v);
|
|
20
|
-
else e.setAttribute(k, v);
|
|
21
|
-
});
|
|
22
|
-
if (children) children.forEach(c => { if (typeof c === 'string') e.appendChild(document.createTextNode(c)); else if (c) e.appendChild(c); });
|
|
23
|
-
return e;
|
|
24
|
-
}
|
|
25
|
-
`;
|
|
26
|
-
}
|
|
27
|
-
//# sourceMappingURL=el.js.map
|
package/dist/shared/el.js.map
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"el.js","sourceRoot":"","sources":["../../src/shared/el.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;CAYlB,CAAC;AACF,CAAC"}
|
|
@@ -1,15 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pagination helpers — `paginateTable`, `paginateGroupedRows`, and the
|
|
3
|
-
* page-button renderer.
|
|
4
|
-
*
|
|
5
|
-
* Every data-table in the dashboard paginates at 10 rows/page (or
|
|
6
|
-
* 10 groups/page when expander rows are present). The grouped variant
|
|
7
|
-
* keeps a data row and its trailing `.expander-row` together so they
|
|
8
|
-
* page as one unit.
|
|
9
|
-
*
|
|
10
|
-
* `renderPageButtons` is shared between both paginators; the checks
|
|
11
|
-
* catalog declares its own paginator inline that also calls this
|
|
12
|
-
* helper, so it must be in scope before any caller.
|
|
13
|
-
*/
|
|
14
|
-
export declare function dashboardPaginationJs(): string;
|
|
15
|
-
//# sourceMappingURL=pagination.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/shared/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,wBAAgB,qBAAqB,IAAI,MAAM,CAkG9C"}
|
|
@@ -1,113 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Pagination helpers — `paginateTable`, `paginateGroupedRows`, and the
|
|
3
|
-
* page-button renderer.
|
|
4
|
-
*
|
|
5
|
-
* Every data-table in the dashboard paginates at 10 rows/page (or
|
|
6
|
-
* 10 groups/page when expander rows are present). The grouped variant
|
|
7
|
-
* keeps a data row and its trailing `.expander-row` together so they
|
|
8
|
-
* page as one unit.
|
|
9
|
-
*
|
|
10
|
-
* `renderPageButtons` is shared between both paginators; the checks
|
|
11
|
-
* catalog declares its own paginator inline that also calls this
|
|
12
|
-
* helper, so it must be in scope before any caller.
|
|
13
|
-
*/
|
|
14
|
-
export function dashboardPaginationJs() {
|
|
15
|
-
return String.raw `
|
|
16
|
-
// =======================================================
|
|
17
|
-
// PAGINATION HELPERS
|
|
18
|
-
// =======================================================
|
|
19
|
-
|
|
20
|
-
function renderPageButtons(container, currentPage, totalPages, goToPage) {
|
|
21
|
-
container.appendChild(el('button', {class:'pagination-btn' + (currentPage === 0 ? ' disabled' : ''), text:'← Prev', onclick: () => { if (currentPage > 0) goToPage(currentPage - 1); }}));
|
|
22
|
-
|
|
23
|
-
const pages = [];
|
|
24
|
-
for (let p = 0; p < totalPages; p++) {
|
|
25
|
-
if (p < 2 || p >= totalPages - 2 || Math.abs(p - currentPage) <= 1) {
|
|
26
|
-
pages.push(p);
|
|
27
|
-
} else if (pages.length > 0 && pages[pages.length - 1] !== -1) {
|
|
28
|
-
pages.push(-1);
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
pages.forEach(p => {
|
|
33
|
-
if (p === -1) {
|
|
34
|
-
container.appendChild(el('span', {style:'color:var(--text-dim);padding:4px 4px;font-size:12px', text:'…'}));
|
|
35
|
-
} else {
|
|
36
|
-
container.appendChild(el('button', {class:'pagination-btn' + (p === currentPage ? ' active' : ''), text: ''+(p+1), onclick: () => goToPage(p)}));
|
|
37
|
-
}
|
|
38
|
-
});
|
|
39
|
-
|
|
40
|
-
container.appendChild(el('button', {class:'pagination-btn' + (currentPage >= totalPages-1 ? ' disabled' : ''), text:'Next →', onclick: () => { if (currentPage < totalPages-1) goToPage(currentPage + 1); }}));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function paginateTable(tbody, paginationContainer, pageSize) {
|
|
44
|
-
const rows = Array.from(tbody.children);
|
|
45
|
-
let currentPage = 0;
|
|
46
|
-
const totalPages = Math.max(1, Math.ceil(rows.length / pageSize));
|
|
47
|
-
|
|
48
|
-
function renderPage() {
|
|
49
|
-
const start = currentPage * pageSize;
|
|
50
|
-
const end = start + pageSize;
|
|
51
|
-
rows.forEach((row, i) => { row.style.display = (i >= start && i < end) ? '' : 'none'; });
|
|
52
|
-
|
|
53
|
-
while (paginationContainer.firstChild) paginationContainer.removeChild(paginationContainer.firstChild);
|
|
54
|
-
if (rows.length <= pageSize) return;
|
|
55
|
-
|
|
56
|
-
const info = el('div', {class:'pagination-info', text: 'Showing ' + (start+1) + '-' + Math.min(end, rows.length) + ' of ' + rows.length});
|
|
57
|
-
paginationContainer.appendChild(info);
|
|
58
|
-
|
|
59
|
-
const btns = el('div', {class:'pagination-btns'});
|
|
60
|
-
renderPageButtons(btns, currentPage, totalPages, (p) => { currentPage = p; renderPage(); });
|
|
61
|
-
paginationContainer.appendChild(btns);
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
renderPage();
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function paginateGroupedRows(tbody, paginationContainer, pageSize) {
|
|
68
|
-
const allRows = Array.from(tbody.children);
|
|
69
|
-
const groups = [];
|
|
70
|
-
for (let i = 0; i < allRows.length; i++) {
|
|
71
|
-
const row = allRows[i];
|
|
72
|
-
if (row.classList.contains('expander-row')) continue;
|
|
73
|
-
const group = [row];
|
|
74
|
-
if (i + 1 < allRows.length && allRows[i+1].classList.contains('expander-row')) {
|
|
75
|
-
group.push(allRows[i+1]);
|
|
76
|
-
}
|
|
77
|
-
groups.push(group);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
let currentPage = 0;
|
|
81
|
-
const totalPages = Math.max(1, Math.ceil(groups.length / pageSize));
|
|
82
|
-
|
|
83
|
-
function renderPage() {
|
|
84
|
-
const start = currentPage * pageSize;
|
|
85
|
-
const end = start + pageSize;
|
|
86
|
-
groups.forEach((group, i) => {
|
|
87
|
-
const visible = i >= start && i < end;
|
|
88
|
-
group.forEach(row => {
|
|
89
|
-
if (row.classList.contains('expander-row')) {
|
|
90
|
-
row.dataset.paged = visible ? 'yes' : 'no';
|
|
91
|
-
if (!visible) row.style.display = 'none';
|
|
92
|
-
} else {
|
|
93
|
-
row.style.display = visible ? '' : 'none';
|
|
94
|
-
}
|
|
95
|
-
});
|
|
96
|
-
});
|
|
97
|
-
|
|
98
|
-
while (paginationContainer.firstChild) paginationContainer.removeChild(paginationContainer.firstChild);
|
|
99
|
-
if (groups.length <= pageSize) return;
|
|
100
|
-
|
|
101
|
-
const info = el('div', {class:'pagination-info', text: 'Showing ' + (start+1) + '-' + Math.min(end, groups.length) + ' of ' + groups.length + ' checks'});
|
|
102
|
-
paginationContainer.appendChild(info);
|
|
103
|
-
|
|
104
|
-
const btns = el('div', {class:'pagination-btns'});
|
|
105
|
-
renderPageButtons(btns, currentPage, totalPages, (p) => { currentPage = p; renderPage(); });
|
|
106
|
-
paginationContainer.appendChild(btns);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
renderPage();
|
|
110
|
-
}
|
|
111
|
-
`;
|
|
112
|
-
}
|
|
113
|
-
//# sourceMappingURL=pagination.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/shared/pagination.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB;IACnC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAgGlB,CAAC;AACF,CAAC"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sortable-table activation.
|
|
3
|
-
*
|
|
4
|
-
* `makeSortable(table)` wires click handlers to each `<th>` so columns
|
|
5
|
-
* can be sorted asc/desc with a numeric/date/string fallback. Keeps
|
|
6
|
-
* any trailing `.expander-row` glued to its parent during sort.
|
|
7
|
-
*
|
|
8
|
-
* After all rendering, a `setTimeout(0)` pass scans the DOM for
|
|
9
|
-
* `.data-table.sortable` elements and activates each — this catches
|
|
10
|
-
* tables created during the synchronous render but defers the
|
|
11
|
-
* activation until after `renderXxxTab()` calls have returned.
|
|
12
|
-
*/
|
|
13
|
-
export declare function dashboardSortableJs(): string;
|
|
14
|
-
//# sourceMappingURL=sortable.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sortable.d.ts","sourceRoot":"","sources":["../../src/shared/sortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAuF5C"}
|
package/dist/shared/sortable.js
DELETED
|
@@ -1,101 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Sortable-table activation.
|
|
3
|
-
*
|
|
4
|
-
* `makeSortable(table)` wires click handlers to each `<th>` so columns
|
|
5
|
-
* can be sorted asc/desc with a numeric/date/string fallback. Keeps
|
|
6
|
-
* any trailing `.expander-row` glued to its parent during sort.
|
|
7
|
-
*
|
|
8
|
-
* After all rendering, a `setTimeout(0)` pass scans the DOM for
|
|
9
|
-
* `.data-table.sortable` elements and activates each — this catches
|
|
10
|
-
* tables created during the synchronous render but defers the
|
|
11
|
-
* activation until after `renderXxxTab()` calls have returned.
|
|
12
|
-
*/
|
|
13
|
-
export function dashboardSortableJs() {
|
|
14
|
-
return String.raw `
|
|
15
|
-
// =======================================================
|
|
16
|
-
// SORTABLE TABLE COLUMNS
|
|
17
|
-
// =======================================================
|
|
18
|
-
|
|
19
|
-
function makeSortable(table) {
|
|
20
|
-
const thead = table.querySelector('thead');
|
|
21
|
-
const tbody = table.querySelector('tbody');
|
|
22
|
-
if (!thead || !tbody) return;
|
|
23
|
-
|
|
24
|
-
const headers = Array.from(thead.querySelectorAll('th'));
|
|
25
|
-
let sortCol = -1;
|
|
26
|
-
let sortAsc = true;
|
|
27
|
-
|
|
28
|
-
headers.forEach((th, colIdx) => {
|
|
29
|
-
if (!th.textContent.trim()) return; // skip empty headers (arrow column)
|
|
30
|
-
th.style.cursor = 'pointer';
|
|
31
|
-
th.style.userSelect = 'none';
|
|
32
|
-
th.addEventListener('click', () => {
|
|
33
|
-
if (sortCol === colIdx) {
|
|
34
|
-
sortAsc = !sortAsc;
|
|
35
|
-
} else {
|
|
36
|
-
sortCol = colIdx;
|
|
37
|
-
sortAsc = true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
// Update sort indicators
|
|
41
|
-
headers.forEach(h => { h.dataset.sort = ''; });
|
|
42
|
-
th.dataset.sort = sortAsc ? 'asc' : 'desc';
|
|
43
|
-
|
|
44
|
-
// Collect data rows with their expander rows
|
|
45
|
-
const allRows = Array.from(tbody.children);
|
|
46
|
-
const groups = [];
|
|
47
|
-
for (let i = 0; i < allRows.length; i++) {
|
|
48
|
-
const row = allRows[i];
|
|
49
|
-
if (row.classList.contains('expander-row')) continue;
|
|
50
|
-
const group = [row];
|
|
51
|
-
if (i + 1 < allRows.length && allRows[i+1].classList.contains('expander-row')) {
|
|
52
|
-
group.push(allRows[i+1]);
|
|
53
|
-
}
|
|
54
|
-
groups.push(group);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
groups.sort((a, b) => {
|
|
58
|
-
const aText = (a[0].children[colIdx]?.textContent || '').trim();
|
|
59
|
-
const bText = (b[0].children[colIdx]?.textContent || '').trim();
|
|
60
|
-
// Try numeric comparison
|
|
61
|
-
const aNum = parseFloat(aText);
|
|
62
|
-
const bNum = parseFloat(bText);
|
|
63
|
-
if (!isNaN(aNum) && !isNaN(bNum)) {
|
|
64
|
-
return sortAsc ? aNum - bNum : bNum - aNum;
|
|
65
|
-
}
|
|
66
|
-
// Date detection (contains / or -)
|
|
67
|
-
const aDate = Date.parse(aText);
|
|
68
|
-
const bDate = Date.parse(bText);
|
|
69
|
-
if (!isNaN(aDate) && !isNaN(bDate)) {
|
|
70
|
-
return sortAsc ? aDate - bDate : bDate - aDate;
|
|
71
|
-
}
|
|
72
|
-
// String comparison
|
|
73
|
-
return sortAsc ? aText.localeCompare(bText) : bText.localeCompare(aText);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
// Reorder DOM — append each group (data row + optional expander)
|
|
77
|
-
groups.forEach(group => {
|
|
78
|
-
group.forEach(row => tbody.appendChild(row));
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// Re-paginate if a pagination container exists after the table
|
|
82
|
-
const pagContainer = table.parentElement?.querySelector('.pagination');
|
|
83
|
-
if (pagContainer) {
|
|
84
|
-
const hasExpanders = groups.some(g => g.length > 1);
|
|
85
|
-
if (hasExpanders) {
|
|
86
|
-
paginateGroupedRows(tbody, pagContainer, 10);
|
|
87
|
-
} else {
|
|
88
|
-
paginateTable(tbody, pagContainer, 10);
|
|
89
|
-
}
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// After all rendering: init sorting
|
|
96
|
-
setTimeout(() => {
|
|
97
|
-
document.querySelectorAll('.data-table.sortable').forEach(t => makeSortable(t));
|
|
98
|
-
}, 0);
|
|
99
|
-
`;
|
|
100
|
-
}
|
|
101
|
-
//# sourceMappingURL=sortable.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"sortable.js","sourceRoot":"","sources":["../../src/shared/sortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,mBAAmB;IACjC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAqFlB,CAAC;AACF,CAAC"}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tab activator registry — runtime side.
|
|
3
|
-
*
|
|
4
|
-
* Decouples cross-tab navigation from "tab X is loaded into the page"
|
|
5
|
-
* guards. The Overview row-click handler asks the registry to
|
|
6
|
-
* activate the tab for a given session; each tab tooling (Code Paths
|
|
7
|
-
* today; future tabs like fit-detail, sim-detail, etc.) registers
|
|
8
|
-
* its activator at module init.
|
|
9
|
-
*
|
|
10
|
-
* New tabs that need session-aware deep-linking should call
|
|
11
|
-
* `registerTabActivator(<session.tool>, fn)` at the top of their
|
|
12
|
-
* JS-string emitter — the same place `dashboardCodePathsJs()` does
|
|
13
|
-
* for `'graph'`.
|
|
14
|
-
*/
|
|
15
|
-
export declare function dashboardTabActivatorsJs(): string;
|
|
16
|
-
//# sourceMappingURL=tab-activators.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tab-activators.d.ts","sourceRoot":"","sources":["../../src/shared/tab-activators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,wBAAgB,wBAAwB,IAAI,MAAM,CAiBjD"}
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tab activator registry — runtime side.
|
|
3
|
-
*
|
|
4
|
-
* Decouples cross-tab navigation from "tab X is loaded into the page"
|
|
5
|
-
* guards. The Overview row-click handler asks the registry to
|
|
6
|
-
* activate the tab for a given session; each tab tooling (Code Paths
|
|
7
|
-
* today; future tabs like fit-detail, sim-detail, etc.) registers
|
|
8
|
-
* its activator at module init.
|
|
9
|
-
*
|
|
10
|
-
* New tabs that need session-aware deep-linking should call
|
|
11
|
-
* `registerTabActivator(<session.tool>, fn)` at the top of their
|
|
12
|
-
* JS-string emitter — the same place `dashboardCodePathsJs()` does
|
|
13
|
-
* for `'graph'`.
|
|
14
|
-
*/
|
|
15
|
-
export function dashboardTabActivatorsJs() {
|
|
16
|
-
return String.raw `
|
|
17
|
-
// =======================================================
|
|
18
|
-
// TAB ACTIVATOR REGISTRY
|
|
19
|
-
// =======================================================
|
|
20
|
-
const tabActivators = {};
|
|
21
|
-
function registerTabActivator(key, fn) {
|
|
22
|
-
tabActivators[key] = fn;
|
|
23
|
-
}
|
|
24
|
-
function activateTabForSession(session) {
|
|
25
|
-
if (!session) return false;
|
|
26
|
-
const fn = tabActivators[session.tool];
|
|
27
|
-
if (typeof fn !== 'function') return false;
|
|
28
|
-
fn(session.id);
|
|
29
|
-
return true;
|
|
30
|
-
}
|
|
31
|
-
`;
|
|
32
|
-
}
|
|
33
|
-
//# sourceMappingURL=tab-activators.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"tab-activators.js","sourceRoot":"","sources":["../../src/shared/tab-activators.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,wBAAwB;IACtC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;CAelB,CAAC;AACF,CAAC"}
|