@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.
Files changed (309) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +8 -0
  3. package/README.md +31 -0
  4. package/dist/__tests__/catalog-provenance.test.d.ts +11 -0
  5. package/dist/__tests__/catalog-provenance.test.d.ts.map +1 -0
  6. package/dist/__tests__/catalog-provenance.test.js +130 -0
  7. package/dist/__tests__/catalog-provenance.test.js.map +1 -0
  8. package/dist/__tests__/coupling-attribution.test.d.ts +9 -0
  9. package/dist/__tests__/coupling-attribution.test.d.ts.map +1 -0
  10. package/dist/__tests__/coupling-attribution.test.js +99 -0
  11. package/dist/__tests__/coupling-attribution.test.js.map +1 -0
  12. package/dist/__tests__/dashboard-bundle-weight.test.d.ts +16 -0
  13. package/dist/__tests__/dashboard-bundle-weight.test.d.ts.map +1 -0
  14. package/dist/__tests__/dashboard-bundle-weight.test.js +73 -0
  15. package/dist/__tests__/dashboard-bundle-weight.test.js.map +1 -0
  16. package/dist/__tests__/dashboard-cell-containment.test.d.ts +2 -0
  17. package/dist/__tests__/dashboard-cell-containment.test.d.ts.map +1 -0
  18. package/dist/__tests__/dashboard-cell-containment.test.js +49 -0
  19. package/dist/__tests__/dashboard-cell-containment.test.js.map +1 -0
  20. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts +10 -0
  21. package/dist/__tests__/dashboard-cytoscape-vendor.test.d.ts.map +1 -0
  22. package/dist/__tests__/dashboard-cytoscape-vendor.test.js +40 -0
  23. package/dist/__tests__/dashboard-cytoscape-vendor.test.js.map +1 -0
  24. package/dist/__tests__/dashboard-editor-link.test.d.ts +5 -0
  25. package/dist/__tests__/dashboard-editor-link.test.d.ts.map +1 -0
  26. package/dist/__tests__/dashboard-editor-link.test.js +36 -0
  27. package/dist/__tests__/dashboard-editor-link.test.js.map +1 -0
  28. package/dist/__tests__/dashboard-filters.test.d.ts +9 -0
  29. package/dist/__tests__/dashboard-filters.test.d.ts.map +1 -0
  30. package/dist/__tests__/dashboard-filters.test.js +95 -0
  31. package/dist/__tests__/dashboard-filters.test.js.map +1 -0
  32. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts +9 -0
  33. package/dist/__tests__/dashboard-function-card-singleton.test.d.ts.map +1 -0
  34. package/dist/__tests__/dashboard-function-card-singleton.test.js +87 -0
  35. package/dist/__tests__/dashboard-function-card-singleton.test.js.map +1 -0
  36. package/dist/__tests__/dashboard-function-card.test.d.ts +10 -0
  37. package/dist/__tests__/dashboard-function-card.test.d.ts.map +1 -0
  38. package/dist/__tests__/dashboard-function-card.test.js +403 -0
  39. package/dist/__tests__/dashboard-function-card.test.js.map +1 -0
  40. package/dist/__tests__/dashboard-function-row.test.d.ts +11 -0
  41. package/dist/__tests__/dashboard-function-row.test.d.ts.map +1 -0
  42. package/dist/__tests__/dashboard-function-row.test.js +101 -0
  43. package/dist/__tests__/dashboard-function-row.test.js.map +1 -0
  44. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts +9 -0
  45. package/dist/__tests__/dashboard-generator-graph-catalog.test.d.ts.map +1 -0
  46. package/dist/__tests__/dashboard-generator-graph-catalog.test.js +75 -0
  47. package/dist/__tests__/dashboard-generator-graph-catalog.test.js.map +1 -0
  48. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts +13 -0
  49. package/dist/__tests__/dashboard-graph-offline.integration.test.d.ts.map +1 -0
  50. package/dist/__tests__/dashboard-graph-offline.integration.test.js +55 -0
  51. package/dist/__tests__/dashboard-graph-offline.integration.test.js.map +1 -0
  52. package/dist/__tests__/dashboard-graph-scc.test.d.ts +17 -0
  53. package/dist/__tests__/dashboard-graph-scc.test.d.ts.map +1 -0
  54. package/dist/__tests__/dashboard-graph-scc.test.js +89 -0
  55. package/dist/__tests__/dashboard-graph-scc.test.js.map +1 -0
  56. package/dist/__tests__/dashboard-graph-view-model.test.d.ts +12 -0
  57. package/dist/__tests__/dashboard-graph-view-model.test.d.ts.map +1 -0
  58. package/dist/__tests__/dashboard-graph-view-model.test.js +331 -0
  59. package/dist/__tests__/dashboard-graph-view-model.test.js.map +1 -0
  60. package/dist/__tests__/dashboard-help-drawer.test.d.ts +9 -0
  61. package/dist/__tests__/dashboard-help-drawer.test.d.ts.map +1 -0
  62. package/dist/__tests__/dashboard-help-drawer.test.js +101 -0
  63. package/dist/__tests__/dashboard-help-drawer.test.js.map +1 -0
  64. package/dist/__tests__/dashboard-html.test.d.ts +2 -0
  65. package/dist/__tests__/dashboard-html.test.d.ts.map +1 -0
  66. package/dist/__tests__/dashboard-html.test.js +169 -0
  67. package/dist/__tests__/dashboard-html.test.js.map +1 -0
  68. package/dist/__tests__/dashboard-indexes.test.d.ts +9 -0
  69. package/dist/__tests__/dashboard-indexes.test.d.ts.map +1 -0
  70. package/dist/__tests__/dashboard-indexes.test.js +211 -0
  71. package/dist/__tests__/dashboard-indexes.test.js.map +1 -0
  72. package/dist/__tests__/dashboard-path-utils.test.d.ts +6 -0
  73. package/dist/__tests__/dashboard-path-utils.test.d.ts.map +1 -0
  74. package/dist/__tests__/dashboard-path-utils.test.js +54 -0
  75. package/dist/__tests__/dashboard-path-utils.test.js.map +1 -0
  76. package/dist/__tests__/dashboard-search.test.d.ts +5 -0
  77. package/dist/__tests__/dashboard-search.test.d.ts.map +1 -0
  78. package/dist/__tests__/dashboard-search.test.js +46 -0
  79. package/dist/__tests__/dashboard-search.test.js.map +1 -0
  80. package/dist/__tests__/dashboard-sessions.test.d.ts +14 -0
  81. package/dist/__tests__/dashboard-sessions.test.d.ts.map +1 -0
  82. package/dist/__tests__/dashboard-sessions.test.js +330 -0
  83. package/dist/__tests__/dashboard-sessions.test.js.map +1 -0
  84. package/dist/__tests__/dashboard-trace.test.d.ts +5 -0
  85. package/dist/__tests__/dashboard-trace.test.d.ts.map +1 -0
  86. package/dist/__tests__/dashboard-trace.test.js +147 -0
  87. package/dist/__tests__/dashboard-trace.test.js.map +1 -0
  88. package/dist/__tests__/dashboard-validation.integration.test.d.ts +14 -0
  89. package/dist/__tests__/dashboard-validation.integration.test.d.ts.map +1 -0
  90. package/dist/__tests__/dashboard-validation.integration.test.js +221 -0
  91. package/dist/__tests__/dashboard-validation.integration.test.js.map +1 -0
  92. package/dist/__tests__/dashboard-view-conformance.test.d.ts +12 -0
  93. package/dist/__tests__/dashboard-view-conformance.test.d.ts.map +1 -0
  94. package/dist/__tests__/dashboard-view-conformance.test.js +58 -0
  95. package/dist/__tests__/dashboard-view-conformance.test.js.map +1 -0
  96. package/dist/__tests__/dashboard-view-coupling.test.d.ts +7 -0
  97. package/dist/__tests__/dashboard-view-coupling.test.d.ts.map +1 -0
  98. package/dist/__tests__/dashboard-view-coupling.test.js +381 -0
  99. package/dist/__tests__/dashboard-view-coupling.test.js.map +1 -0
  100. package/dist/__tests__/dashboard-view-distribution.test.d.ts +10 -0
  101. package/dist/__tests__/dashboard-view-distribution.test.d.ts.map +1 -0
  102. package/dist/__tests__/dashboard-view-distribution.test.js +272 -0
  103. package/dist/__tests__/dashboard-view-distribution.test.js.map +1 -0
  104. package/dist/__tests__/dashboard-view-graph.test.d.ts +13 -0
  105. package/dist/__tests__/dashboard-view-graph.test.d.ts.map +1 -0
  106. package/dist/__tests__/dashboard-view-graph.test.js +332 -0
  107. package/dist/__tests__/dashboard-view-graph.test.js.map +1 -0
  108. package/dist/__tests__/dashboard-view-template.test.d.ts +21 -0
  109. package/dist/__tests__/dashboard-view-template.test.d.ts.map +1 -0
  110. package/dist/__tests__/dashboard-view-template.test.js +153 -0
  111. package/dist/__tests__/dashboard-view-template.test.js.map +1 -0
  112. package/dist/__tests__/dashboard.test.d.ts +2 -0
  113. package/dist/__tests__/dashboard.test.d.ts.map +1 -0
  114. package/dist/__tests__/dashboard.test.js +129 -0
  115. package/dist/__tests__/dashboard.test.js.map +1 -0
  116. package/dist/__tests__/graph-tab.test.d.ts +10 -0
  117. package/dist/__tests__/graph-tab.test.d.ts.map +1 -0
  118. package/dist/__tests__/graph-tab.test.js +76 -0
  119. package/dist/__tests__/graph-tab.test.js.map +1 -0
  120. package/dist/checks.d.ts +7 -0
  121. package/dist/checks.d.ts.map +1 -0
  122. package/dist/checks.js +283 -0
  123. package/dist/checks.js.map +1 -0
  124. package/dist/code-paths/__tests__/views-registry.test.d.ts +13 -0
  125. package/dist/code-paths/__tests__/views-registry.test.d.ts.map +1 -0
  126. package/dist/code-paths/__tests__/views-registry.test.js +39 -0
  127. package/dist/code-paths/__tests__/views-registry.test.js.map +1 -0
  128. package/dist/code-paths/catalog-provenance.d.ts +22 -0
  129. package/dist/code-paths/catalog-provenance.d.ts.map +1 -0
  130. package/dist/code-paths/catalog-provenance.js +108 -0
  131. package/dist/code-paths/catalog-provenance.js.map +1 -0
  132. package/dist/code-paths/catalog-recipes-tables.d.ts +11 -0
  133. package/dist/code-paths/catalog-recipes-tables.d.ts.map +1 -0
  134. package/dist/code-paths/catalog-recipes-tables.js +86 -0
  135. package/dist/code-paths/catalog-recipes-tables.js.map +1 -0
  136. package/dist/code-paths/cytoscape-vendor.d.ts +27 -0
  137. package/dist/code-paths/cytoscape-vendor.d.ts.map +1 -0
  138. package/dist/code-paths/cytoscape-vendor.js +68 -0
  139. package/dist/code-paths/cytoscape-vendor.js.map +1 -0
  140. package/dist/code-paths/editor-link.d.ts +10 -0
  141. package/dist/code-paths/editor-link.d.ts.map +1 -0
  142. package/dist/code-paths/editor-link.js +20 -0
  143. package/dist/code-paths/editor-link.js.map +1 -0
  144. package/dist/code-paths/filters.d.ts +19 -0
  145. package/dist/code-paths/filters.d.ts.map +1 -0
  146. package/dist/code-paths/filters.js +47 -0
  147. package/dist/code-paths/filters.js.map +1 -0
  148. package/dist/code-paths/function-card.d.ts +15 -0
  149. package/dist/code-paths/function-card.d.ts.map +1 -0
  150. package/dist/code-paths/function-card.js +169 -0
  151. package/dist/code-paths/function-card.js.map +1 -0
  152. package/dist/code-paths/function-row.d.ts +17 -0
  153. package/dist/code-paths/function-row.d.ts.map +1 -0
  154. package/dist/code-paths/function-row.js +77 -0
  155. package/dist/code-paths/function-row.js.map +1 -0
  156. package/dist/code-paths/graph-controls.d.ts +27 -0
  157. package/dist/code-paths/graph-controls.d.ts.map +1 -0
  158. package/dist/code-paths/graph-controls.js +257 -0
  159. package/dist/code-paths/graph-controls.js.map +1 -0
  160. package/dist/code-paths/graph-scc.d.ts +32 -0
  161. package/dist/code-paths/graph-scc.d.ts.map +1 -0
  162. package/dist/code-paths/graph-scc.js +136 -0
  163. package/dist/code-paths/graph-scc.js.map +1 -0
  164. package/dist/code-paths/graph-stylesheet.d.ts +22 -0
  165. package/dist/code-paths/graph-stylesheet.d.ts.map +1 -0
  166. package/dist/code-paths/graph-stylesheet.js +121 -0
  167. package/dist/code-paths/graph-stylesheet.js.map +1 -0
  168. package/dist/code-paths/graph-view-model.d.ts +120 -0
  169. package/dist/code-paths/graph-view-model.d.ts.map +1 -0
  170. package/dist/code-paths/graph-view-model.js +199 -0
  171. package/dist/code-paths/graph-view-model.js.map +1 -0
  172. package/dist/code-paths/help-drawer.d.ts +18 -0
  173. package/dist/code-paths/help-drawer.d.ts.map +1 -0
  174. package/dist/code-paths/help-drawer.js +54 -0
  175. package/dist/code-paths/help-drawer.js.map +1 -0
  176. package/dist/code-paths/indexes.d.ts +28 -0
  177. package/dist/code-paths/indexes.d.ts.map +1 -0
  178. package/dist/code-paths/indexes.js +97 -0
  179. package/dist/code-paths/indexes.js.map +1 -0
  180. package/dist/code-paths/path-utils.d.ts +15 -0
  181. package/dist/code-paths/path-utils.d.ts.map +1 -0
  182. package/dist/code-paths/path-utils.js +47 -0
  183. package/dist/code-paths/path-utils.js.map +1 -0
  184. package/dist/code-paths/search.d.ts +14 -0
  185. package/dist/code-paths/search.d.ts.map +1 -0
  186. package/dist/code-paths/search.js +54 -0
  187. package/dist/code-paths/search.js.map +1 -0
  188. package/dist/code-paths/trace.d.ts +11 -0
  189. package/dist/code-paths/trace.d.ts.map +1 -0
  190. package/dist/code-paths/trace.js +60 -0
  191. package/dist/code-paths/trace.js.map +1 -0
  192. package/dist/code-paths/view-coupling.d.ts +22 -0
  193. package/dist/code-paths/view-coupling.d.ts.map +1 -0
  194. package/dist/code-paths/view-coupling.js +218 -0
  195. package/dist/code-paths/view-coupling.js.map +1 -0
  196. package/dist/code-paths/view-distribution.d.ts +20 -0
  197. package/dist/code-paths/view-distribution.d.ts.map +1 -0
  198. package/dist/code-paths/view-distribution.js +82 -0
  199. package/dist/code-paths/view-distribution.js.map +1 -0
  200. package/dist/code-paths/view-graph.d.ts +35 -0
  201. package/dist/code-paths/view-graph.d.ts.map +1 -0
  202. package/dist/code-paths/view-graph.js +379 -0
  203. package/dist/code-paths/view-graph.js.map +1 -0
  204. package/dist/code-paths/view-template.d.ts +154 -0
  205. package/dist/code-paths/view-template.d.ts.map +1 -0
  206. package/dist/code-paths/view-template.js +218 -0
  207. package/dist/code-paths/view-template.js.map +1 -0
  208. package/dist/code-paths/views-registry.d.ts +13 -0
  209. package/dist/code-paths/views-registry.d.ts.map +1 -0
  210. package/dist/code-paths/views-registry.js +53 -0
  211. package/dist/code-paths/views-registry.js.map +1 -0
  212. package/dist/code-paths.d.ts +69 -0
  213. package/dist/code-paths.d.ts.map +1 -0
  214. package/dist/code-paths.js +356 -0
  215. package/dist/code-paths.js.map +1 -0
  216. package/dist/css/cards.d.ts +9 -0
  217. package/dist/css/cards.d.ts.map +1 -0
  218. package/dist/css/cards.js +36 -0
  219. package/dist/css/cards.js.map +1 -0
  220. package/dist/css/code-paths.d.ts +9 -0
  221. package/dist/css/code-paths.d.ts.map +1 -0
  222. package/dist/css/code-paths.js +111 -0
  223. package/dist/css/code-paths.js.map +1 -0
  224. package/dist/css/data-table.d.ts +12 -0
  225. package/dist/css/data-table.d.ts.map +1 -0
  226. package/dist/css/data-table.js +103 -0
  227. package/dist/css/data-table.js.map +1 -0
  228. package/dist/css/function-card.d.ts +6 -0
  229. package/dist/css/function-card.d.ts.map +1 -0
  230. package/dist/css/function-card.js +26 -0
  231. package/dist/css/function-card.js.map +1 -0
  232. package/dist/css/help-drawer.d.ts +6 -0
  233. package/dist/css/help-drawer.d.ts.map +1 -0
  234. package/dist/css/help-drawer.js +22 -0
  235. package/dist/css/help-drawer.js.map +1 -0
  236. package/dist/css/tabs.d.ts +9 -0
  237. package/dist/css/tabs.d.ts.map +1 -0
  238. package/dist/css/tabs.js +28 -0
  239. package/dist/css/tabs.js.map +1 -0
  240. package/dist/css/theme.d.ts +8 -0
  241. package/dist/css/theme.d.ts.map +1 -0
  242. package/dist/css/theme.js +34 -0
  243. package/dist/css/theme.js.map +1 -0
  244. package/dist/css.d.ts +13 -0
  245. package/dist/css.d.ts.map +1 -0
  246. package/dist/css.js +30 -0
  247. package/dist/css.js.map +1 -0
  248. package/dist/generator.d.ts +33 -0
  249. package/dist/generator.d.ts.map +1 -0
  250. package/dist/generator.js +161 -0
  251. package/dist/generator.js.map +1 -0
  252. package/dist/index.d.ts +21 -0
  253. package/dist/index.d.ts.map +1 -0
  254. package/dist/index.js +20 -0
  255. package/dist/index.js.map +1 -0
  256. package/dist/overview.d.ts +13 -0
  257. package/dist/overview.d.ts.map +1 -0
  258. package/dist/overview.js +91 -0
  259. package/dist/overview.js.map +1 -0
  260. package/dist/recipes.d.ts +6 -0
  261. package/dist/recipes.d.ts.map +1 -0
  262. package/dist/recipes.js +68 -0
  263. package/dist/recipes.js.map +1 -0
  264. package/dist/sessions.d.ts +6 -0
  265. package/dist/sessions.d.ts.map +1 -0
  266. package/dist/sessions.js +288 -0
  267. package/dist/sessions.js.map +1 -0
  268. package/dist/shared/el.d.ts +13 -0
  269. package/dist/shared/el.d.ts.map +1 -0
  270. package/dist/shared/el.js +27 -0
  271. package/dist/shared/el.js.map +1 -0
  272. package/dist/shared/pagination.d.ts +15 -0
  273. package/dist/shared/pagination.d.ts.map +1 -0
  274. package/dist/shared/pagination.js +113 -0
  275. package/dist/shared/pagination.js.map +1 -0
  276. package/dist/shared/sortable.d.ts +14 -0
  277. package/dist/shared/sortable.d.ts.map +1 -0
  278. package/dist/shared/sortable.js +101 -0
  279. package/dist/shared/sortable.js.map +1 -0
  280. package/dist/shared/tab-activators.d.ts +16 -0
  281. package/dist/shared/tab-activators.d.ts.map +1 -0
  282. package/dist/shared/tab-activators.js +33 -0
  283. package/dist/shared/tab-activators.js.map +1 -0
  284. package/dist/shared/tab-bar.d.ts +8 -0
  285. package/dist/shared/tab-bar.d.ts.map +1 -0
  286. package/dist/shared/tab-bar.js +20 -0
  287. package/dist/shared/tab-bar.js.map +1 -0
  288. package/dist/shared.d.ts +26 -0
  289. package/dist/shared.d.ts.map +1 -0
  290. package/dist/shared.js +39 -0
  291. package/dist/shared.js.map +1 -0
  292. package/dist/subtab-bar.d.ts +23 -0
  293. package/dist/subtab-bar.d.ts.map +1 -0
  294. package/dist/subtab-bar.js +77 -0
  295. package/dist/subtab-bar.js.map +1 -0
  296. package/dist/tool-tab-registry.d.ts +76 -0
  297. package/dist/tool-tab-registry.d.ts.map +1 -0
  298. package/dist/tool-tab-registry.js +44 -0
  299. package/dist/tool-tab-registry.js.map +1 -0
  300. package/dist/tool-tabs-registrations.d.ts +19 -0
  301. package/dist/tool-tabs-registrations.d.ts.map +1 -0
  302. package/dist/tool-tabs-registrations.js +46 -0
  303. package/dist/tool-tabs-registrations.js.map +1 -0
  304. package/dist/tool-tabs.d.ts +12 -0
  305. package/dist/tool-tabs.d.ts.map +1 -0
  306. package/dist/tool-tabs.js +80 -0
  307. package/dist/tool-tabs.js.map +1 -0
  308. package/dist/vendor/cytoscape-bundle.js +600 -0
  309. 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"}
@@ -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"}