@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,113 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,14 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sortable.d.ts","sourceRoot":"","sources":["../../src/shared/sortable.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,wBAAgB,mBAAmB,IAAI,MAAM,CAuF5C"}
|
|
@@ -0,0 +1,101 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
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
|
|
@@ -0,0 +1 @@
|
|
|
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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level tab-bar click handler.
|
|
3
|
+
*
|
|
4
|
+
* Wires the `#tab-bar` click event to toggle the `active` class on
|
|
5
|
+
* both the `.tab` headers and the `.tab-panel` containers.
|
|
6
|
+
*/
|
|
7
|
+
export declare function dashboardTabBarJs(): string;
|
|
8
|
+
//# sourceMappingURL=tab-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-bar.d.ts","sourceRoot":"","sources":["../../src/shared/tab-bar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,wBAAgB,iBAAiB,IAAI,MAAM,CAY1C"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Top-level tab-bar click handler.
|
|
3
|
+
*
|
|
4
|
+
* Wires the `#tab-bar` click event to toggle the `active` class on
|
|
5
|
+
* both the `.tab` headers and the `.tab-panel` containers.
|
|
6
|
+
*/
|
|
7
|
+
export function dashboardTabBarJs() {
|
|
8
|
+
return String.raw `
|
|
9
|
+
// Tab switching
|
|
10
|
+
document.getElementById('tab-bar').addEventListener('click', e => {
|
|
11
|
+
const tab = e.target.closest('.tab');
|
|
12
|
+
if (!tab) return;
|
|
13
|
+
document.querySelectorAll('.tab').forEach(t => t.classList.remove('active'));
|
|
14
|
+
document.querySelectorAll('.tab-panel').forEach(p => p.classList.remove('active'));
|
|
15
|
+
tab.classList.add('active');
|
|
16
|
+
document.getElementById('panel-' + tab.dataset.tab).classList.add('active');
|
|
17
|
+
});
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=tab-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tab-bar.js","sourceRoot":"","sources":["../../src/shared/tab-bar.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB;IAC/B,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;CAUlB,CAAC;AACF,CAAC"}
|
package/dist/shared.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dashboard JS — concatenates the per-concern emitters in
|
|
3
|
+
* `shared/`.
|
|
4
|
+
*
|
|
5
|
+
* Pre-F9 this was a 237-line `String.raw` blob covering five
|
|
6
|
+
* concerns. Each concern now lives in its own file and is composed
|
|
7
|
+
* here in the order downstream emitters depend on:
|
|
8
|
+
*
|
|
9
|
+
* 1. tab-bar — top-level tab switching
|
|
10
|
+
* 2. tab-activators — cross-tab session-aware navigation registry
|
|
11
|
+
* 3. el — `el(tag, attrs, children)` DOM helper used by
|
|
12
|
+
* every subsequent emitter
|
|
13
|
+
* 4. pagination — `paginateTable` / `paginateGroupedRows` /
|
|
14
|
+
* `renderPageButtons`
|
|
15
|
+
* 5. sortable — `makeSortable` plus the global setTimeout(0)
|
|
16
|
+
* scan that activates `.data-table.sortable`
|
|
17
|
+
*
|
|
18
|
+
* Any change to the order should be considered carefully — the
|
|
19
|
+
* pagination helpers reference `el`, the sortable helper references
|
|
20
|
+
* the pagination helpers, and the global activation pass at the end
|
|
21
|
+
* fires after every preceding emitter has declared its top-level
|
|
22
|
+
* names. New shared concerns should pick a slot rather than be
|
|
23
|
+
* appended blindly.
|
|
24
|
+
*/
|
|
25
|
+
export declare function dashboardSharedJs(): string;
|
|
26
|
+
//# sourceMappingURL=shared.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAQH,wBAAgB,iBAAiB,IAAI,MAAM,CAQ1C"}
|
package/dist/shared.js
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared dashboard JS — concatenates the per-concern emitters in
|
|
3
|
+
* `shared/`.
|
|
4
|
+
*
|
|
5
|
+
* Pre-F9 this was a 237-line `String.raw` blob covering five
|
|
6
|
+
* concerns. Each concern now lives in its own file and is composed
|
|
7
|
+
* here in the order downstream emitters depend on:
|
|
8
|
+
*
|
|
9
|
+
* 1. tab-bar — top-level tab switching
|
|
10
|
+
* 2. tab-activators — cross-tab session-aware navigation registry
|
|
11
|
+
* 3. el — `el(tag, attrs, children)` DOM helper used by
|
|
12
|
+
* every subsequent emitter
|
|
13
|
+
* 4. pagination — `paginateTable` / `paginateGroupedRows` /
|
|
14
|
+
* `renderPageButtons`
|
|
15
|
+
* 5. sortable — `makeSortable` plus the global setTimeout(0)
|
|
16
|
+
* scan that activates `.data-table.sortable`
|
|
17
|
+
*
|
|
18
|
+
* Any change to the order should be considered carefully — the
|
|
19
|
+
* pagination helpers reference `el`, the sortable helper references
|
|
20
|
+
* the pagination helpers, and the global activation pass at the end
|
|
21
|
+
* fires after every preceding emitter has declared its top-level
|
|
22
|
+
* names. New shared concerns should pick a slot rather than be
|
|
23
|
+
* appended blindly.
|
|
24
|
+
*/
|
|
25
|
+
import { dashboardElJs } from './shared/el.js';
|
|
26
|
+
import { dashboardPaginationJs } from './shared/pagination.js';
|
|
27
|
+
import { dashboardSortableJs } from './shared/sortable.js';
|
|
28
|
+
import { dashboardTabActivatorsJs } from './shared/tab-activators.js';
|
|
29
|
+
import { dashboardTabBarJs } from './shared/tab-bar.js';
|
|
30
|
+
export function dashboardSharedJs() {
|
|
31
|
+
return [
|
|
32
|
+
dashboardTabBarJs(),
|
|
33
|
+
dashboardTabActivatorsJs(),
|
|
34
|
+
dashboardElJs(),
|
|
35
|
+
dashboardPaginationJs(),
|
|
36
|
+
dashboardSortableJs(),
|
|
37
|
+
].join('\n');
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=shared.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../src/shared.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAC/C,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAExD,MAAM,UAAU,iBAAiB;IAC/B,OAAO;QACL,iBAAiB,EAAE;QACnB,wBAAwB,EAAE;QAC1B,aAAa,EAAE;QACf,qBAAqB,EAAE;QACvB,mBAAmB,EAAE;KACtB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subtab-bar Strategy — JS-string emitter for the shared subtab pattern.
|
|
3
|
+
*
|
|
4
|
+
* Both the fit/sim Tool Tab (Sessions / Catalog / Recipes — three
|
|
5
|
+
* subtabs) and the Code Paths Tab (Sessions / Explore — two subtabs)
|
|
6
|
+
* need the same DOM/click-delegation behaviour: a `.subtab-bar` of
|
|
7
|
+
* clickable headers, a stack of `.subtab-panel` containers, and a
|
|
8
|
+
* single click handler that toggles the `active` class on both.
|
|
9
|
+
*
|
|
10
|
+
* Pre-F2, both call sites duplicated the same 20-line block. This
|
|
11
|
+
* emitter declares one runtime helper, `renderSubtabBar(panel,
|
|
12
|
+
* subtabs)`, that both consumers call. The Strategy is the
|
|
13
|
+
* `subtabs` array — each entry is `{ id, label, render(panel) }` —
|
|
14
|
+
* and `renderSubtabBar` returns the panel-element map so callers can
|
|
15
|
+
* still reach into specific subpanels if they need to (Code Paths
|
|
16
|
+
* does not, fit/sim's `renderToolTab` does not either after F2).
|
|
17
|
+
*
|
|
18
|
+
* The emitter must be concatenated BEFORE any caller (i.e. before
|
|
19
|
+
* `dashboardToolTabsJs` and `dashboardCodePathsJs`) since both rely
|
|
20
|
+
* on `renderSubtabBar` being declared in scope.
|
|
21
|
+
*/
|
|
22
|
+
export declare function dashboardSubtabBarJs(): string;
|
|
23
|
+
//# sourceMappingURL=subtab-bar.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtab-bar.d.ts","sourceRoot":"","sources":["../src/subtab-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,oBAAoB,IAAI,MAAM,CAsD7C"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Subtab-bar Strategy — JS-string emitter for the shared subtab pattern.
|
|
3
|
+
*
|
|
4
|
+
* Both the fit/sim Tool Tab (Sessions / Catalog / Recipes — three
|
|
5
|
+
* subtabs) and the Code Paths Tab (Sessions / Explore — two subtabs)
|
|
6
|
+
* need the same DOM/click-delegation behaviour: a `.subtab-bar` of
|
|
7
|
+
* clickable headers, a stack of `.subtab-panel` containers, and a
|
|
8
|
+
* single click handler that toggles the `active` class on both.
|
|
9
|
+
*
|
|
10
|
+
* Pre-F2, both call sites duplicated the same 20-line block. This
|
|
11
|
+
* emitter declares one runtime helper, `renderSubtabBar(panel,
|
|
12
|
+
* subtabs)`, that both consumers call. The Strategy is the
|
|
13
|
+
* `subtabs` array — each entry is `{ id, label, render(panel) }` —
|
|
14
|
+
* and `renderSubtabBar` returns the panel-element map so callers can
|
|
15
|
+
* still reach into specific subpanels if they need to (Code Paths
|
|
16
|
+
* does not, fit/sim's `renderToolTab` does not either after F2).
|
|
17
|
+
*
|
|
18
|
+
* The emitter must be concatenated BEFORE any caller (i.e. before
|
|
19
|
+
* `dashboardToolTabsJs` and `dashboardCodePathsJs`) since both rely
|
|
20
|
+
* on `renderSubtabBar` being declared in scope.
|
|
21
|
+
*/
|
|
22
|
+
export function dashboardSubtabBarJs() {
|
|
23
|
+
return String.raw `
|
|
24
|
+
// =======================================================
|
|
25
|
+
// SUBTAB BAR (Strategy — shared by tool tabs and Code Paths)
|
|
26
|
+
// =======================================================
|
|
27
|
+
//
|
|
28
|
+
// renderSubtabBar(panel, subtabs)
|
|
29
|
+
// panel — host element (e.g. document.getElementById('panel-fitness'))
|
|
30
|
+
// subtabs — Array<{ id: string, label: string, render(panel): void }>
|
|
31
|
+
//
|
|
32
|
+
// Builds the .subtab-bar (with the first subtab .active), creates one
|
|
33
|
+
// .subtab-panel per entry, mounts them, wires up click delegation,
|
|
34
|
+
// and finally invokes each entry's render(panel) to populate it.
|
|
35
|
+
//
|
|
36
|
+
// Returns the { id → panel } map so callers can reach into a specific
|
|
37
|
+
// subpanel by id if they need to (rare; both first-party callers
|
|
38
|
+
// don't).
|
|
39
|
+
function renderSubtabBar(panel, subtabs) {
|
|
40
|
+
const subtabBar = el('div', { class: 'subtab-bar' });
|
|
41
|
+
const panels = {};
|
|
42
|
+
subtabs.forEach((t, i) => {
|
|
43
|
+
const subtab = el('div', {
|
|
44
|
+
class: 'subtab' + (i === 0 ? ' active' : ''),
|
|
45
|
+
'data-subtab': t.id,
|
|
46
|
+
text: t.label,
|
|
47
|
+
});
|
|
48
|
+
subtabBar.appendChild(subtab);
|
|
49
|
+
|
|
50
|
+
const subpanel = el('div', {
|
|
51
|
+
class: 'subtab-panel' + (i === 0 ? ' active' : ''),
|
|
52
|
+
id: panel.id + '-' + t.id,
|
|
53
|
+
});
|
|
54
|
+
panels[t.id] = subpanel;
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
panel.appendChild(subtabBar);
|
|
58
|
+
subtabs.forEach(t => panel.appendChild(panels[t.id]));
|
|
59
|
+
|
|
60
|
+
subtabBar.addEventListener('click', e => {
|
|
61
|
+
const tab = e.target.closest('.subtab');
|
|
62
|
+
if (!tab) return;
|
|
63
|
+
subtabBar.querySelectorAll('.subtab').forEach(t => t.classList.remove('active'));
|
|
64
|
+
tab.classList.add('active');
|
|
65
|
+
subtabs.forEach(t => panels[t.id].classList.remove('active'));
|
|
66
|
+
panels[tab.dataset.subtab].classList.add('active');
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
// Render each subpanel's body. Done after mounting so renderers can
|
|
70
|
+
// safely measure their host (the panel is in the document).
|
|
71
|
+
subtabs.forEach(t => t.render(panels[t.id]));
|
|
72
|
+
|
|
73
|
+
return panels;
|
|
74
|
+
}
|
|
75
|
+
`;
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=subtab-bar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"subtab-bar.js","sourceRoot":"","sources":["../src/subtab-bar.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,UAAU,oBAAoB;IAClC,OAAO,MAAM,CAAC,GAAG,CAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAoDlB,CAAC;AACF,CAAC"}
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool tab registry — the extension point for top-level tabs.
|
|
3
|
+
*
|
|
4
|
+
* `generator.ts` walks the registry to emit (1) the tab buttons in the
|
|
5
|
+
* top-level `.tab-bar`, (2) the per-tab `<div id="panel-…">` containers,
|
|
6
|
+
* (3) the per-tab `render*Tab()` calls in the inlined `<script>`, and
|
|
7
|
+
* (4) Overview's `tool → tab` and badge-style maps. Adding a new tool
|
|
8
|
+
* tab is a `defineToolTab` call plus shipping the tool's `render*Tab`
|
|
9
|
+
* JS-string emitter — no central-dispatcher edits.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors `defineRankedView` (Code Paths) and `tabActivators`
|
|
12
|
+
* (cross-tab navigation): a single descriptor type + a registry +
|
|
13
|
+
* iteration in the generator.
|
|
14
|
+
*
|
|
15
|
+
* The Overview tab is intentionally NOT in this registry — it is a
|
|
16
|
+
* cross-tool aggregate by design and lives outside the per-tool
|
|
17
|
+
* abstraction.
|
|
18
|
+
*
|
|
19
|
+
* **Why not Registry<T>?** Per the runscope+registry plan's Phase 0
|
|
20
|
+
* Task 0.1 decision (D6), `ToolTabRegistry` deliberately stays an
|
|
21
|
+
* append-only `ToolTabDescriptor[]` — it has no `id+name+tags` shape,
|
|
22
|
+
* no duplicate-handling semantics, and is registration-order-sensitive
|
|
23
|
+
* (tab-bar order matters). The kernel's `Registry<T>` would add no
|
|
24
|
+
* value here. The cross-cutting T2 audit explicitly noted that this
|
|
25
|
+
* registry has "a different shape and may stay separate."
|
|
26
|
+
*/
|
|
27
|
+
/**
|
|
28
|
+
* Descriptor for a top-level tool tab (Fitness, Simulation, Code
|
|
29
|
+
* Paths, …). All fields are required to keep the registry shape
|
|
30
|
+
* predictable; tools that don't carry per-session state (e.g. a
|
|
31
|
+
* future "audit" tool with no detail view) still supply a `tool`
|
|
32
|
+
* key — Overview's row-click handler uses it for the tabMap.
|
|
33
|
+
*/
|
|
34
|
+
export interface ToolTabDescriptor {
|
|
35
|
+
/**
|
|
36
|
+
* The DOM tab id, used for `data-tab="<id>"` and `panel-<id>`.
|
|
37
|
+
* Examples: `'fitness'`, `'simulation'`, `'code-paths'`.
|
|
38
|
+
*/
|
|
39
|
+
id: string;
|
|
40
|
+
/**
|
|
41
|
+
* The `StoredSession.tool` key whose sessions belong on this tab.
|
|
42
|
+
* Examples: `'fit'`, `'sim'`, `'graph'`. Used by Overview to map
|
|
43
|
+
* a session to a tab and by `tabActivators` for deep-link routing.
|
|
44
|
+
*/
|
|
45
|
+
tool: string;
|
|
46
|
+
/** Tab label, e.g. `'Fitness'`. */
|
|
47
|
+
label: string;
|
|
48
|
+
/** SVG markup for the tab icon. Spliced verbatim into the `.tab` div. */
|
|
49
|
+
icon: string;
|
|
50
|
+
/**
|
|
51
|
+
* Inline `style` value for the `.badge` element rendered for this
|
|
52
|
+
* tool in Overview's Recent Activity table. Example:
|
|
53
|
+
* `'background:rgba(124,160,104,0.15);color:var(--accent-fitness)'`.
|
|
54
|
+
*/
|
|
55
|
+
badgeStyle: string;
|
|
56
|
+
/**
|
|
57
|
+
* Name of the JS-side `render*Tab()` function the tool's emitter
|
|
58
|
+
* declares. The generator emits a call to this name in the inlined
|
|
59
|
+
* `<script>` after all emitters run. Must be a plain identifier
|
|
60
|
+
* (no parentheses) — the generator appends `();`.
|
|
61
|
+
*/
|
|
62
|
+
renderFunctionName: string;
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Register a top-level tool tab. Called at module load by every tool
|
|
66
|
+
* that ships a tab (today: fit, sim, graph). Order of registration
|
|
67
|
+
* controls tab-bar order; the existing fit/sim/graph order is what
|
|
68
|
+
* pre-F1 hard-coded, so callers should preserve it.
|
|
69
|
+
*/
|
|
70
|
+
export declare function defineToolTab(descriptor: ToolTabDescriptor): void;
|
|
71
|
+
/**
|
|
72
|
+
* Snapshot of the current registry. Returned as a fresh array so
|
|
73
|
+
* callers can iterate without worrying about concurrent registration.
|
|
74
|
+
*/
|
|
75
|
+
export declare function listToolTabs(): ToolTabDescriptor[];
|
|
76
|
+
//# sourceMappingURL=tool-tab-registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-tab-registry.d.ts","sourceRoot":"","sources":["../src/tool-tab-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAEH;;;;;;GAMG;AACH,MAAM,WAAW,iBAAiB;IAChC;;;OAGG;IACH,EAAE,EAAE,MAAM,CAAC;IACX;;;;OAIG;IACH,IAAI,EAAE,MAAM,CAAC;IACb,mCAAmC;IACnC,KAAK,EAAE,MAAM,CAAC;IACd,yEAAyE;IACzE,IAAI,EAAE,MAAM,CAAC;IACb;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IACnB;;;;;OAKG;IACH,kBAAkB,EAAE,MAAM,CAAC;CAC5B;AAID;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI,CAEjE;AAED;;;GAGG;AACH,wBAAgB,YAAY,IAAI,iBAAiB,EAAE,CAElD"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tool tab registry — the extension point for top-level tabs.
|
|
3
|
+
*
|
|
4
|
+
* `generator.ts` walks the registry to emit (1) the tab buttons in the
|
|
5
|
+
* top-level `.tab-bar`, (2) the per-tab `<div id="panel-…">` containers,
|
|
6
|
+
* (3) the per-tab `render*Tab()` calls in the inlined `<script>`, and
|
|
7
|
+
* (4) Overview's `tool → tab` and badge-style maps. Adding a new tool
|
|
8
|
+
* tab is a `defineToolTab` call plus shipping the tool's `render*Tab`
|
|
9
|
+
* JS-string emitter — no central-dispatcher edits.
|
|
10
|
+
*
|
|
11
|
+
* Mirrors `defineRankedView` (Code Paths) and `tabActivators`
|
|
12
|
+
* (cross-tab navigation): a single descriptor type + a registry +
|
|
13
|
+
* iteration in the generator.
|
|
14
|
+
*
|
|
15
|
+
* The Overview tab is intentionally NOT in this registry — it is a
|
|
16
|
+
* cross-tool aggregate by design and lives outside the per-tool
|
|
17
|
+
* abstraction.
|
|
18
|
+
*
|
|
19
|
+
* **Why not Registry<T>?** Per the runscope+registry plan's Phase 0
|
|
20
|
+
* Task 0.1 decision (D6), `ToolTabRegistry` deliberately stays an
|
|
21
|
+
* append-only `ToolTabDescriptor[]` — it has no `id+name+tags` shape,
|
|
22
|
+
* no duplicate-handling semantics, and is registration-order-sensitive
|
|
23
|
+
* (tab-bar order matters). The kernel's `Registry<T>` would add no
|
|
24
|
+
* value here. The cross-cutting T2 audit explicitly noted that this
|
|
25
|
+
* registry has "a different shape and may stay separate."
|
|
26
|
+
*/
|
|
27
|
+
const registry = [];
|
|
28
|
+
/**
|
|
29
|
+
* Register a top-level tool tab. Called at module load by every tool
|
|
30
|
+
* that ships a tab (today: fit, sim, graph). Order of registration
|
|
31
|
+
* controls tab-bar order; the existing fit/sim/graph order is what
|
|
32
|
+
* pre-F1 hard-coded, so callers should preserve it.
|
|
33
|
+
*/
|
|
34
|
+
export function defineToolTab(descriptor) {
|
|
35
|
+
registry.push(descriptor);
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Snapshot of the current registry. Returned as a fresh array so
|
|
39
|
+
* callers can iterate without worrying about concurrent registration.
|
|
40
|
+
*/
|
|
41
|
+
export function listToolTabs() {
|
|
42
|
+
return [...registry];
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=tool-tab-registry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"tool-tab-registry.js","sourceRoot":"","sources":["../src/tool-tab-registry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AAwCH,MAAM,QAAQ,GAAwB,EAAE,CAAC;AAEzC;;;;;GAKG;AACH,MAAM,UAAU,aAAa,CAAC,UAA6B;IACzD,QAAQ,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;AAC5B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY;IAC1B,OAAO,CAAC,GAAG,QAAQ,CAAC,CAAC;AACvB,CAAC"}
|