web-mojo 2.2.101 → 2.2.102

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 (195) hide show
  1. package/CHANGELOG.md +596 -0
  2. package/README.md +2 -2
  3. package/dist/admin-models.cjs.js +2 -0
  4. package/dist/admin-models.cjs.js.map +1 -0
  5. package/dist/admin-models.es.js +2 -0
  6. package/dist/admin-models.es.js.map +1 -0
  7. package/dist/admin.cjs.js +1 -1
  8. package/dist/admin.css +42 -0
  9. package/dist/admin.es.js +1 -1
  10. package/dist/auth.cjs.js +1 -1
  11. package/dist/auth.es.js +1 -1
  12. package/dist/charts.cjs.js +1 -1
  13. package/dist/charts.cjs.js.map +1 -1
  14. package/dist/charts.css +897 -1
  15. package/dist/charts.es.js +1 -1
  16. package/dist/charts.es.js.map +1 -1
  17. package/dist/chat.css +96 -0
  18. package/dist/chunks/AssistantPanelView-CMRTtoqS.js +2 -0
  19. package/dist/chunks/AssistantPanelView-CMRTtoqS.js.map +1 -0
  20. package/dist/chunks/AssistantPanelView-CaVkWhVD.js +2 -0
  21. package/dist/chunks/AssistantPanelView-CaVkWhVD.js.map +1 -0
  22. package/dist/chunks/ChatView-B73uox2v.js +2 -0
  23. package/dist/chunks/ChatView-B73uox2v.js.map +1 -0
  24. package/dist/chunks/ChatView-W8daOwIo.js +2 -0
  25. package/dist/chunks/ChatView-W8daOwIo.js.map +1 -0
  26. package/dist/chunks/Collection-BZlmtcuL.js +2 -0
  27. package/dist/chunks/Collection-BZlmtcuL.js.map +1 -0
  28. package/dist/chunks/Collection-Bwoq6muu.js +2 -0
  29. package/dist/chunks/Collection-Bwoq6muu.js.map +1 -0
  30. package/dist/chunks/ContextMenu-BPPtuqKk.js +2 -0
  31. package/dist/chunks/ContextMenu-BPPtuqKk.js.map +1 -0
  32. package/dist/chunks/ContextMenu-q76hjQb6.js +2 -0
  33. package/dist/chunks/ContextMenu-q76hjQb6.js.map +1 -0
  34. package/dist/chunks/DataView-BbrwHMV4.js +2 -0
  35. package/dist/chunks/{DataView-BFx2glFg.js.map → DataView-BbrwHMV4.js.map} +1 -1
  36. package/dist/chunks/DataView-k-7wmk5_.js +2 -0
  37. package/dist/chunks/{DataView-D5C_lDdg.js.map → DataView-k-7wmk5_.js.map} +1 -1
  38. package/dist/chunks/FormView-DPSuwWMq.js +3 -0
  39. package/dist/chunks/{FormView-e-PeRx1s.js.map → FormView-DPSuwWMq.js.map} +1 -1
  40. package/dist/chunks/FormView-Dcy7XOtC.js +3 -0
  41. package/dist/chunks/{FormView-Cu4iPfvU.js.map → FormView-Dcy7XOtC.js.map} +1 -1
  42. package/dist/chunks/ListView-DHC-yBIw.js +2 -0
  43. package/dist/chunks/ListView-DHC-yBIw.js.map +1 -0
  44. package/dist/chunks/ListView-iGBsD4a7.js +2 -0
  45. package/dist/chunks/ListView-iGBsD4a7.js.map +1 -0
  46. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js +2 -0
  47. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js.map +1 -0
  48. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js +2 -0
  49. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js.map +1 -0
  50. package/dist/chunks/Modal-DBJU16cc.js +3 -0
  51. package/dist/chunks/Modal-DBJU16cc.js.map +1 -0
  52. package/dist/chunks/Modal-DuULCMFZ.js +3 -0
  53. package/dist/chunks/Modal-DuULCMFZ.js.map +1 -0
  54. package/dist/chunks/Passkeys-CGRZ8ZMv.js +2 -0
  55. package/dist/chunks/{Passkeys-DfVHrRPY.js.map → Passkeys-CGRZ8ZMv.js.map} +1 -1
  56. package/dist/chunks/Passkeys-Dr8-oSm9.js +2 -0
  57. package/dist/chunks/{Passkeys-Bj-ufmei.js.map → Passkeys-Dr8-oSm9.js.map} +1 -1
  58. package/dist/chunks/TokenManager-CFsr1qUV.js +2 -0
  59. package/dist/chunks/TokenManager-CFsr1qUV.js.map +1 -0
  60. package/dist/chunks/TokenManager-CHQxK_e5.js +2 -0
  61. package/dist/chunks/TokenManager-CHQxK_e5.js.map +1 -0
  62. package/dist/chunks/User-DNQhdBtI.js +2 -0
  63. package/dist/chunks/User-DNQhdBtI.js.map +1 -0
  64. package/dist/chunks/User-Dg7xpYEI.js +2 -0
  65. package/dist/chunks/User-Dg7xpYEI.js.map +1 -0
  66. package/dist/chunks/UserProfileView-B5nczdfw.js +2 -0
  67. package/dist/chunks/UserProfileView-B5nczdfw.js.map +1 -0
  68. package/dist/chunks/UserProfileView-Bpz3VZmP.js +2 -0
  69. package/dist/chunks/UserProfileView-Bpz3VZmP.js.map +1 -0
  70. package/dist/chunks/View-C5n3sIFi.js +2 -0
  71. package/dist/chunks/View-C5n3sIFi.js.map +1 -0
  72. package/dist/chunks/View-Yazho7OL.js +2 -0
  73. package/dist/chunks/View-Yazho7OL.js.map +1 -0
  74. package/dist/chunks/WebApp-CeiDNV6L.js +2 -0
  75. package/dist/chunks/WebApp-CeiDNV6L.js.map +1 -0
  76. package/dist/chunks/WebApp-irKlhuFX.js +2 -0
  77. package/dist/chunks/WebApp-irKlhuFX.js.map +1 -0
  78. package/dist/chunks/admin-BkxeK68u.js +2 -0
  79. package/dist/chunks/admin-BkxeK68u.js.map +1 -0
  80. package/dist/chunks/admin-vjoNbv_1.js +2 -0
  81. package/dist/chunks/admin-vjoNbv_1.js.map +1 -0
  82. package/dist/chunks/exportChart-DbsHDCxw.js +2 -0
  83. package/dist/chunks/exportChart-DbsHDCxw.js.map +1 -0
  84. package/dist/chunks/exportChart-Dk8D_du5.js +2 -0
  85. package/dist/chunks/exportChart-Dk8D_du5.js.map +1 -0
  86. package/dist/chunks/index-BNjCQA7q.js +2 -0
  87. package/dist/chunks/{index-BY54viKF.js.map → index-BNjCQA7q.js.map} +1 -1
  88. package/dist/chunks/index-DBsIDOAa.js +2 -0
  89. package/dist/chunks/{index-Df5lx5TH.js.map → index-DBsIDOAa.js.map} +1 -1
  90. package/dist/chunks/{version-8mBBYRDe.js → version-B0cBv8MN.js} +2 -2
  91. package/dist/chunks/{version-8mBBYRDe.js.map → version-B0cBv8MN.js.map} +1 -1
  92. package/dist/chunks/{version-CoLHxZIU.js → version-DtqCY0ZY.js} +2 -2
  93. package/dist/chunks/{version-CoLHxZIU.js.map → version-DtqCY0ZY.js.map} +1 -1
  94. package/dist/core.css +306 -0
  95. package/dist/css/web-mojo.css +1 -1
  96. package/dist/docit.cjs.js +1 -1
  97. package/dist/docit.cjs.js.map +1 -1
  98. package/dist/docit.es.js +1 -1
  99. package/dist/docit.es.js.map +1 -1
  100. package/dist/index.cjs.js +1 -1
  101. package/dist/index.cjs.js.map +1 -1
  102. package/dist/index.es.js +1 -1
  103. package/dist/index.es.js.map +1 -1
  104. package/dist/lightbox.cjs.js +1 -1
  105. package/dist/lightbox.cjs.js.map +1 -1
  106. package/dist/lightbox.es.js +1 -1
  107. package/dist/lightbox.es.js.map +1 -1
  108. package/dist/map.cjs.js +1 -1
  109. package/dist/map.cjs.js.map +1 -1
  110. package/dist/map.es.js +1 -1
  111. package/dist/map.es.js.map +1 -1
  112. package/dist/portal.css +86 -0
  113. package/dist/timeline.cjs.js +1 -1
  114. package/dist/timeline.cjs.js.map +1 -1
  115. package/dist/timeline.es.js +1 -1
  116. package/dist/timeline.es.js.map +1 -1
  117. package/dist/user-profile.cjs.js +1 -1
  118. package/dist/user-profile.es.js +1 -1
  119. package/dist/web-mojo.lite.iife.js +4183 -3916
  120. package/dist/web-mojo.lite.iife.js.map +1 -1
  121. package/dist/web-mojo.lite.iife.min.js +289 -311
  122. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  123. package/package.json +7 -2
  124. package/dist/chunks/AssistantPanelView-Bdpmd4z7.js +0 -2
  125. package/dist/chunks/AssistantPanelView-Bdpmd4z7.js.map +0 -1
  126. package/dist/chunks/AssistantPanelView-C0bdbEWr.js +0 -2
  127. package/dist/chunks/AssistantPanelView-C0bdbEWr.js.map +0 -1
  128. package/dist/chunks/ChatView-B1MZNPGy.js +0 -2
  129. package/dist/chunks/ChatView-B1MZNPGy.js.map +0 -1
  130. package/dist/chunks/ChatView-DXl9nVVV.js +0 -2
  131. package/dist/chunks/ChatView-DXl9nVVV.js.map +0 -1
  132. package/dist/chunks/Collection-C39Oy2q0.js +0 -2
  133. package/dist/chunks/Collection-C39Oy2q0.js.map +0 -1
  134. package/dist/chunks/Collection-CyK0u557.js +0 -2
  135. package/dist/chunks/Collection-CyK0u557.js.map +0 -1
  136. package/dist/chunks/ContextMenu-D-C7V6J6.js +0 -2
  137. package/dist/chunks/ContextMenu-D-C7V6J6.js.map +0 -1
  138. package/dist/chunks/ContextMenu-hjqR1pGW.js +0 -2
  139. package/dist/chunks/ContextMenu-hjqR1pGW.js.map +0 -1
  140. package/dist/chunks/DataView-BFx2glFg.js +0 -2
  141. package/dist/chunks/DataView-D5C_lDdg.js +0 -2
  142. package/dist/chunks/Dialog-1umNJi4B.js +0 -3
  143. package/dist/chunks/Dialog-1umNJi4B.js.map +0 -1
  144. package/dist/chunks/Dialog-BnxWLMfr.js +0 -3
  145. package/dist/chunks/Dialog-BnxWLMfr.js.map +0 -1
  146. package/dist/chunks/FormView-Cu4iPfvU.js +0 -3
  147. package/dist/chunks/FormView-e-PeRx1s.js +0 -3
  148. package/dist/chunks/ListView-D_hOtfWZ.js +0 -2
  149. package/dist/chunks/ListView-D_hOtfWZ.js.map +0 -1
  150. package/dist/chunks/ListView-Jkke6pU1.js +0 -2
  151. package/dist/chunks/ListView-Jkke6pU1.js.map +0 -1
  152. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js +0 -2
  153. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js.map +0 -1
  154. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js +0 -2
  155. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js.map +0 -1
  156. package/dist/chunks/MetricsMiniChartWidget-BaXxR9C6.js +0 -2
  157. package/dist/chunks/MetricsMiniChartWidget-BaXxR9C6.js.map +0 -1
  158. package/dist/chunks/MetricsMiniChartWidget-DSKmKY2Z.js +0 -2
  159. package/dist/chunks/MetricsMiniChartWidget-DSKmKY2Z.js.map +0 -1
  160. package/dist/chunks/MiniPieChart-B3sM4Bjv.js +0 -2
  161. package/dist/chunks/MiniPieChart-B3sM4Bjv.js.map +0 -1
  162. package/dist/chunks/MiniPieChart-DL5Rynvm.js +0 -2
  163. package/dist/chunks/MiniPieChart-DL5Rynvm.js.map +0 -1
  164. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js +0 -2
  165. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js.map +0 -1
  166. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js +0 -2
  167. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js.map +0 -1
  168. package/dist/chunks/Modal-COT4zRh3.js +0 -2
  169. package/dist/chunks/Modal-COT4zRh3.js.map +0 -1
  170. package/dist/chunks/Modal-DgMMvDnw.js +0 -2
  171. package/dist/chunks/Modal-DgMMvDnw.js.map +0 -1
  172. package/dist/chunks/Passkeys-Bj-ufmei.js +0 -2
  173. package/dist/chunks/Passkeys-DfVHrRPY.js +0 -2
  174. package/dist/chunks/TokenManager-DIEaBGJh.js +0 -2
  175. package/dist/chunks/TokenManager-DIEaBGJh.js.map +0 -1
  176. package/dist/chunks/TokenManager-DeXkJy0u.js +0 -2
  177. package/dist/chunks/TokenManager-DeXkJy0u.js.map +0 -1
  178. package/dist/chunks/UserProfileView-B_jyMUp0.js +0 -2
  179. package/dist/chunks/UserProfileView-B_jyMUp0.js.map +0 -1
  180. package/dist/chunks/UserProfileView-DcpvvGQS.js +0 -2
  181. package/dist/chunks/UserProfileView-DcpvvGQS.js.map +0 -1
  182. package/dist/chunks/WebApp-BvFnKj-I.js +0 -2
  183. package/dist/chunks/WebApp-BvFnKj-I.js.map +0 -1
  184. package/dist/chunks/WebApp-CfDWKmwH.js +0 -2
  185. package/dist/chunks/WebApp-CfDWKmwH.js.map +0 -1
  186. package/dist/chunks/WebSocketClient-BQAZr8C4.js +0 -2
  187. package/dist/chunks/WebSocketClient-BQAZr8C4.js.map +0 -1
  188. package/dist/chunks/WebSocketClient-YR5d82h8.js +0 -2
  189. package/dist/chunks/WebSocketClient-YR5d82h8.js.map +0 -1
  190. package/dist/chunks/admin-BgvcCWQp.js +0 -2
  191. package/dist/chunks/admin-BgvcCWQp.js.map +0 -1
  192. package/dist/chunks/admin-DzhyZ_Tn.js +0 -2
  193. package/dist/chunks/admin-DzhyZ_Tn.js.map +0 -1
  194. package/dist/chunks/index-BY54viKF.js +0 -2
  195. package/dist/chunks/index-Df5lx5TH.js +0 -2
package/CHANGELOG.md CHANGED
@@ -2,7 +2,603 @@
2
2
 
3
3
  ## Unreleased
4
4
 
5
+ ### CSS — Admin assistant panel: dark theme coverage
6
+
7
+ - The Admin extension's AI Assistant panel (`AssistantPanelView` + the
8
+ modal-fullscreen `AssistantView`) now honors `[data-bs-theme="dark"]`.
9
+ Previously the panel header, empty-state hero, suggestion chips,
10
+ composer input, history rail, conversation search, and thinking
11
+ indicator all rendered against hardcoded `#fff` / `#f7f7f8` surfaces —
12
+ loud against the framework's dark portal page (and especially loud
13
+ against the new `#0a0d11` mission-control palette). Each surface now
14
+ picks up `--bs-body-bg` / `--bs-tertiary-bg` / `--bs-secondary-bg`
15
+ under the dark theme. Hover/active states on conversation rows and
16
+ panel header buttons swap their `rgba(0, 0, 0, ...)` tints for the
17
+ matching `rgba(255, 255, 255, ...)` values. Light theme is unchanged;
18
+ no `!important`.
19
+
20
+ ### Feature — Map: disable scroll/zoom interaction at construction time
21
+
22
+ - New constructor options on `MapView`, `MapLibreView`, and (via
23
+ `mapOptions`) `MetricsCountryMapView`:
24
+ - `interactive` (default `true`) — master switch; `false` freezes all
25
+ user interaction (pan, zoom, keyboard, rotate).
26
+ - `scrollZoom`, `dragPan`, `doubleClickZoom`, `keyboard`, `touchZoom`
27
+ (all default `true`) — granular per-handler toggles.
28
+ - Cross-cutting names are translated per backend: `scrollZoom` →
29
+ Leaflet `scrollWheelZoom`, `dragPan` → Leaflet `dragging`, `touchZoom`
30
+ → MapLibre `touchZoomRotate`. Both views accept the same wrapper API.
31
+ - Defaults preserve today's fully-interactive behavior; existing call
32
+ sites are unchanged.
33
+ - `showZoomControl` / `showNavigationControl` remain independent — UI
34
+ buttons can still be shown on a non-interactive map.
35
+ - Programmatic camera changes (`setView()`, `setZoom()`, `flyTo()`,
36
+ `setPitch()`, `setBearing()`) are unaffected; the flags only gate
37
+ user input.
38
+ - Portal example pages (`extensions/map-view`, `extensions/map-libre-view`)
39
+ show both modes side-by-side.
40
+
41
+ ### CSS — Dark theme: deeper mission-control surface as default
42
+
43
+ - The framework's `[data-bs-theme="dark"]` palette now uses the deep
44
+ near-black surfaces previously scoped to `SecurityDashboardPage`:
45
+ page `#0a0d11`, card/tertiary `#11161d`, secondary `#161b22`, border
46
+ `#1f2630`, emphasis text `#e6ecf3`, muted text `#8a96a6`. Every
47
+ dark-mode page in consuming apps will look noticeably deeper and
48
+ more contrasty on upgrade.
49
+ - **Light theme is unchanged.**
50
+ - **Opt out:** apps that want the previous Bootstrap defaults can
51
+ override `--bs-body-bg`, `--bs-tertiary-bg`, etc. in their own CSS
52
+ under `[data-bs-theme="dark"]` — the framework block uses no
53
+ `!important`, so any later/higher-specificity rule wins.
54
+ - **Removed:** the `SecurityDashboardPage`-scoped overrides in
55
+ `charts.css` (`.portal-layout:has(.security-dashboard-page)`,
56
+ `.security-dashboard-page`, and the defensive `.page-container` /
57
+ `.portal-content` fall-throughs). The dashboard now inherits the
58
+ global palette seamlessly — no visual change.
59
+ - **Removed:** the `KPITile` `[data-bs-theme="dark"]` `--mojo-kpi-tile-*`
60
+ variable block. The tile component already falls back through
61
+ `--bs-tertiary-bg` / `--bs-emphasis-color` / `--bs-secondary-color` /
62
+ `--bs-border-color`, which now match the original dashboard values
63
+ 1:1, so the dedicated overrides became redundant. The
64
+ delta-badge and hover tints are kept since they don't map to a
65
+ Bootstrap token.
66
+ - **`--mojo-sidebar-dark-bg`** now drops to `#0d1117` under
67
+ `[data-bs-theme="dark"]` so `topnav-dark` and `sidebar-dark` sit
68
+ one tier above the page (`#0a0d11`) and one tier below cards
69
+ (`#11161d`) — portal chrome reads as a band rather than a raised
70
+ tile. The light-mode default (`#343a40`) is unchanged.
71
+ - **`[data-bs-theme="dark"] .sidebar-light`** now uses
72
+ `var(--bs-secondary-bg)` instead of a hardcoded `#2a2f36`, so the
73
+ rail stays one step above the page automatically and tracks any
74
+ future palette tweak.
75
+ - **Topbar default unchanged:** `--mojo-topnav-bg` still resolves to
76
+ `var(--bs-primary)` (brand-blue topbar) when no `topnav-*` class is
77
+ set. Consumers who want a deep mission-control topbar should use
78
+ `topnav-dark`, which now picks up the new `#0d1117`.
79
+
80
+ ### Changed — Admin sidebar Security menu restructured
81
+
82
+ - **Security Dashboard** is now a top-level sidebar item, placed directly
83
+ below the system **Dashboard** (route `?page=system/incident-dashboard`,
84
+ icon `bi-shield-check`).
85
+ - The single 12-child **Security** group has been split into three smaller
86
+ groups: **System Security** (Tickets, Incidents, Events, Rules),
87
+ **Network Security** (IPs, IP Sets, Blocked, Firewall Log), and
88
+ **Bouncer** (Signals, Devices, Bots).
89
+ - Labels were tightened: `Rule Engine` → `Rules`, `GeoIP` → `IPs`,
90
+ `Blocked IPs` → `Blocked`, `Bouncer Signals` → `Signals`,
91
+ `Bouncer Devices` → `Devices`, `Bot Signatures` → `Bots`.
92
+ - Routes and per-item permissions are unchanged. Pure menu-config edit in
93
+ `src/admin.js`; no page registrations or framework APIs changed.
94
+
95
+ ### Feature — SeriesChart axis label visibility
96
+
97
+ - New `showXLabels` / `showYLabels` options (default `true`) hide the X /
98
+ Y text labels independently. Gridlines (`showGrid`) are unaffected.
99
+ - When labels are hidden, the plot area grows into the freed padding
100
+ (`padBottom` 24→8 with `showXLabels: false`, `padLeft` 40→8 with
101
+ `showYLabels: false`). The X-label auto-rotation extra-padding path is
102
+ skipped when X labels are hidden.
103
+ - Plumbed through `MetricsChart` so dashboard panels can hide axis text
104
+ for compact tile-style displays.
105
+
106
+ ### Behavior — SeriesChart hover-dim is now opt-in
107
+
108
+ - New `highlightOnHover` option on SeriesChart (default `false`). Hovering
109
+ a bar or dot no longer dims the other series — the dim effect was
110
+ visually noisy on stacked-bar charts and distracting in dashboard
111
+ contexts.
112
+ - Pass `highlightOnHover: true` to restore the earlier always-on behavior.
113
+ - Plumbed through `MetricsChart`.
114
+
115
+ ### Behavior — SeriesChart legend default is now top-left
116
+
117
+ - New `legendJustify: 'start' | 'center' | 'end'` option (default
118
+ `'start'`). Combined with the existing `legendPosition: 'top'` default,
119
+ the SeriesChart legend now sits **top-left** instead of top-center.
120
+ - `legendJustify` maps to CSS `justify-content` for both the horizontal
121
+ flex (top/bottom legends) and the column flex (left/right legends).
122
+ - Invalid values fall back to `'start'` with a `console.warn`.
123
+ - To restore the prior top-center look, pass `legendJustify: 'center'`.
124
+ - Plumbed through `MetricsChart` (and via that, every dashboard chart
125
+ built on the metrics fetch path).
126
+
127
+ ### Fixed — Modal: descendant dropdowns/popovers no longer clipped at the card edge
128
+
129
+ - `.modal-content` had `overflow: hidden` (added with the hero-band redesign in
130
+ `ff27795`) which clipped any absolutely-positioned descendant — `MultiSelectDropdown`,
131
+ `ComboBox`, `CollectionMultiSelect`, plain Bootstrap `.dropdown-menu`, and any
132
+ context menu rendered inside a modal body.
133
+ - The hero band's `::before` pseudo-element already declares its own matching
134
+ `border-radius: 14px 14px 0 0`, so the ancestor clip was unnecessary for the
135
+ rounded chrome. Removing `overflow: hidden` restores Bootstrap's default
136
+ modal behavior — popovers can escape the card edge.
137
+ - No JS or component changes; the fix is a single CSS-rule removal in
138
+ `src/core/css/core.css`.
139
+
140
+ ### Feature — Security Dashboard rebuild + new framework primitives
141
+
142
+ - **`SecurityDashboardPage`** replaces the older tabbed
143
+ `IncidentDashboardPage` with a single scrolling mission-control page.
144
+ Route stays `system/incident-dashboard`. Seven sections answer the
145
+ one question a sysadmin actually asks: *what should I be doing right
146
+ now?*
147
+ - **Pulse** — 8 KPI tiles via one batched
148
+ `/api/metrics/series?with_delta=true` + parallel REST counts. Tiles
149
+ track NEW incidents (untriaged), not OPEN (already claimed).
150
+ - **Needs Attention** — list of priority>=8, status=new incidents.
151
+ Click row opens the existing `IncidentView` modal. Hover-revealed
152
+ inline resolve/pause actions for users with `manage_security`.
153
+ - **Threat Composition** — single 30-day stacked bar chart that
154
+ condenses `incident_events` / `firewall:blocks` / `bouncer:blocks`
155
+ / `auth:failures` into one view. 7D / 30D / 90D toggle.
156
+ - **Geography** — `MetricsCountryMapView` with slug-family selector
157
+ (Events / Incidents / Firewall / Logins).
158
+ - **Distributions** — three cards: status donut, priority bucket bars,
159
+ bouncer funnel (assessments → monitors → blocks).
160
+ - **Top Sources** — top IPs + top categories (last 7d). Tries
161
+ server-side `group_by` first; falls back to client-side aggregation
162
+ of recent 500 events when unsupported, with a fallback note in the
163
+ card subtitle.
164
+ - **Auth Failures** — uses the new `auth:failures` aggregate slug
165
+ directly (no client-side composition); 4 sub-tiles for password
166
+ resets / TOTP failures / sessions revoked / accounts deactivated.
167
+ - **System Health** — single `/api/incident/health/summary` call,
168
+ one row per discovered category, color dot from `level`, click row
169
+ drills into the linked incident.
170
+ - Sections 3-7 use **lazy mount** so they don't fetch until scrolled
171
+ into view.
172
+ - Refresh tiers via `Page.scheduleRefresh`: 60s for pulse +
173
+ needs-attention; 5min for everything else; manual refresh button
174
+ fires all tiers.
175
+ - Drill-downs use `Modal.drawer` for day / country / status-filter /
176
+ priority-bucket / IP / category / auth sub-tile clicks.
177
+
178
+ - **New framework primitives** (charts):
179
+ - **`KPITile`** (`web-mojo/charts`) — compact presentation-only tile:
180
+ label, big tabular value, color-coded delta badge, embedded
181
+ `MiniChart` sparkline. Renders pre-fetched data via constructor or
182
+ `setData()`. Click emits `tile:click`. Sits between `MiniChart`
183
+ (sparkline only) and `MetricsMiniChartWidget` (rich self-fetching
184
+ card). Delta rendering rules:
185
+ - `deltaPct` present → "+12%" / "−8%"
186
+ - `deltaPct` omitted (prev=0) + `delta` present → "+4" absolute
187
+ - both null → no badge
188
+ - never renders `Infinity%`
189
+ - `severity` (critical/high/warn/info/good) adds left-stripe accent
190
+ - `tone` ('bad' or 'good') decides whether rising = red or green
191
+ - **`KPIStrip`** (`web-mojo/charts`) — orchestrator for N `KPITile`s.
192
+ Single batched `/api/metrics/series?with_delta=true` call populates
193
+ all metric tiles, parallel REST count calls populate tiles defined
194
+ with `rest:` config, and one batched `/api/metrics/fetch` populates
195
+ sparklines for all metric tiles.
196
+
197
+ - **Extensions to existing components:**
198
+ - **`PieChart`** — new `centerLabel` and `centerSubLabel` options
199
+ render text in the donut center (when `cutout > 0`). Accept either
200
+ a static string or a function called with `({ total, segments })`.
201
+ - **`MetricsChart`** — new `withDelta` flag passes through to the
202
+ series endpoint; new `compactHeader` mode hides the gear menu and
203
+ shrinks the range toggle for use inside dashboard panels.
204
+ - **`Modal.drawer({ eyebrow, title, meta, view })`** — standardised
205
+ drill-down modal header (eyebrow tag, title, meta row of icon-
206
+ prefixed spans). Accepts a `View` instance OR raw HTML body.
207
+ - **`Page.scheduleRefresh(handler, intervalMs, { tier, immediate })`**
208
+ — registers a recurring handler that auto-clears in `onExit`.
209
+ Replaces the `setInterval`/`clearInterval` boilerplate in every
210
+ dashboard. `runScheduledRefreshes(tier?)` fires all (or one tier).
211
+ - **`View.addChild(child, { lazyMount: true })`** — defers the
212
+ child's render until its container scrolls into viewport via
213
+ `IntersectionObserver`. Container gets a 1px placeholder min-height
214
+ so the observer can detect 0-content placeholders. Disconnects on
215
+ destroy. Falls back to immediate render when IO isn't available.
216
+
217
+ - **Examples portal:**
218
+ - New `KPIStripExample` at `extensions/charts/kpi-strip` —
219
+ demonstrates standalone `KPITile`s (delta rules) and `KPIStrip`
220
+ (batched fetch).
221
+ - `PieChartExample` updated to show the new doughnut center label.
222
+
223
+ ### Feature — App-level theme management
224
+
225
+ - **`WebApp` now owns the user's light/dark theme.** New public API:
226
+ - `app.setTheme('light' | 'dark' | 'system')` — persists the preference,
227
+ applies `data-bs-theme` to `<html>`, emits `'theme:changed'` on
228
+ `app.events` with `{ theme, resolved }`.
229
+ - `app.getTheme()` — returns the stored preference.
230
+ - `app.getResolvedTheme()` — returns the currently applied
231
+ `'light' | 'dark'` (resolves `'system'` via `prefers-color-scheme`).
232
+ - **Default preference is `'system'`** — first-time visitors automatically
233
+ get the theme that matches their OS. The `prefers-color-scheme` media
234
+ listener tracks OS theme changes live while the preference is `'system'`.
235
+ - **Storage:** the preference is persisted to `localStorage` under
236
+ `${appName}:theme` (mirrors the existing PortalApp sidebar-state
237
+ pattern). All reads/writes are wrapped in try/catch — private mode and
238
+ disabled storage degrade gracefully.
239
+ - **No flash:** the manager runs in the WebApp constructor so
240
+ `data-bs-theme` is set before the first view renders.
241
+ - **PortalApp auto-injects a topbar theme toggle** into the usermenu:
242
+ Light / Dark / System items with `bi-sun`, `bi-moon-stars`,
243
+ `bi-circle-half` icons. The currently selected option is marked
244
+ active. Opt out with `topbar.themeToggle: false`.
245
+ - **TopNav dropdown items now honor an `active: true` flag** — the
246
+ template renders `class="dropdown-item active"` for selected items
247
+ (used by the new theme toggle and available to any caller).
248
+ - **`examples/portal/app.js` simplified** — the manual `theme-light` /
249
+ `theme-dark` action handlers are gone; the framework toggle handles
250
+ them.
251
+ - **New module:** `src/core/utils/ThemeManager.js`.
252
+
253
+ ### CSS — Dark-theme coverage for sidebar treatments, SideNavView, ChatView, TimelineView
254
+
255
+ - **`sidebar-light` under `data-bs-theme="dark"`** now renders against a
256
+ softer dark surface (`#2a2f36`) instead of bright white. Hover, active,
257
+ group-header, and muted-text selectors all adapt to the dark palette.
258
+ Treatment classes remain independent of the global theme — devs can
259
+ still mix `sidebar-light` / `sidebar-dark` with either.
260
+ - **`sidebar-dark` under `data-bs-theme="dark"`** got a sanity-pass hover
261
+ override so the active state remains distinguishable from the base.
262
+ - **`SideNavView`** now has dark-theme overrides in `portal.css` covering
263
+ the rail bg, active accent, hover, group-label, and dropdown-collapse
264
+ mode. Base inline styles in the component template are unchanged.
265
+ - **`ChatView` (`chat.css`)** picks up dark-theme rules for the
266
+ container, message bubbles (left), input area, attachment states,
267
+ file-attachment overlay, and the WebKit scrollbar. Bubble `right`
268
+ keeps `--bs-primary` from the base rule (theme-aware).
269
+ - **`TimelineView`** ships its own `src/extensions/timeline/timeline.css`
270
+ for the first time — class-based base styles for the connector line,
271
+ marker, dot, content card, and meta surfaces, plus `data-bs-theme="dark"`
272
+ overrides where Bootstrap tokens aren't enough on their own.
273
+ Auto-imported from `TimelineView.js`.
274
+
275
+ ### Refactor — In-`src/` callers migrated from Dialog.* to Modal.* / ModalView
276
+
277
+ - **All in-`src/` callers** migrated from the deprecated `Dialog.*` API
278
+ to the canonical `Modal.*` (static API) / `ModalView` (instance class)
279
+ surface. 60 files touched across `src/core/`, `src/extensions/admin/*`,
280
+ `src/extensions/lightbox/*`, `src/extensions/charts/*`,
281
+ `src/extensions/map/*`, `src/extensions/user-profile/*`.
282
+ - **Pure fire-and-forget `new Dialog({...})` sites** (7) collapsed to
283
+ one-line `Modal.show(view, { size, header, title })` calls.
284
+ - **Instance-handle `new Dialog({...})` sites** (11) now use
285
+ `new ModalView({...})` — same instance API (`on('action:*')`,
286
+ `setLoading`, `element`, `hide()`, `destroy()`) since `Dialog`
287
+ already re-exported `ModalView` under the hood.
288
+ - **`Dialog.show*()` static calls** mechanically renamed: `showDialog
289
+ → dialog`, `showForm → form`, `showModelForm → modelForm`, `showData
290
+ → data`, `showCode → code`, `showModelView → showModelView`,
291
+ `updateModelImage → updateModelImage`, `showBusy/hideBusy` (alias
292
+ preserved on `Modal.*`), `alert/confirm/prompt` (identical signatures).
293
+ - **`WebApp.showLoading/hideLoading/showModelView/showModelForm/showForm/
294
+ showDialog/showAlert`** internal lazy imports now resolve `Modal.js`
295
+ instead of `Dialog.js`.
296
+ - **Pre-existing bug fixed**: `JobHealthView.onActionSystemSettings()`
297
+ called `Dialog.showAlert(...)` — `showAlert` was never wired on the
298
+ shim. The System Settings button now resolves through `Modal.alert`.
299
+ - **`Model.showError()`** also migrated from a (broken, unimported)
300
+ `Dialog.alert(...)` global reference to a dynamic `Modal.alert`
301
+ import, matching the lazy-import pattern WebApp uses.
302
+ - **Public surface unchanged**: the `Dialog.js` shim and the public
303
+ `Dialog` re-exports in `src/index.js` / `src/lite/index.js` remain in
304
+ place for downstream consumers. Their removal is a separate breaking
305
+ change PR.
306
+
307
+ ### Refactor — Dialog.js split into ModalView + Modal + focused helpers
308
+
309
+ - **`Dialog.js` (1,987 lines) split** into focused modules in
310
+ `src/core/views/feedback/`:
311
+ - **`ModalView.js`** — the underlying `View` class. Owns Bootstrap 5
312
+ modal mechanics (lifecycle, sizing, z-index stacking, header/body/
313
+ footer composition, button rendering, context menu).
314
+ - **`Modal.js`** — canonical static API: `dialog`, `show`, `showModel`,
315
+ `showModelView`, `alert`, `confirm`, `prompt`, `form`, `modelForm`,
316
+ `data`, `code`, `htmlPreview`, `updateModelImage`, `loading`. A new
317
+ `_renderAndAwait` helper consolidates ~300 lines of duplicated
318
+ render/show/resolve/destroy code.
319
+ - **`BusyIndicator.js`** — singleton frosted-glass loading overlay.
320
+ - **`CodeViewer.js`** — Prism-highlighted code block view + statics.
321
+ - **`HtmlPreview.js`** — sandboxed iframe preview view.
322
+ - **`Dialog.js`** — thin compatibility shim. Default-exports
323
+ `ModalView`; every legacy static (`Dialog.alert`, `Dialog.showForm`,
324
+ `Dialog.showBusy`, …) is a one-line forward to the matching
325
+ `Modal.*` method. Existing `new Dialog({...})` and `Dialog.show*()`
326
+ callers continue to work unchanged.
327
+ - **Busy-indicator overlays consolidated**. The legacy dark
328
+ `mojo-busy-indicator` is gone; only the modern frosted-card
329
+ `mojo-loading-overlay` remains. `Modal.loading()` / `Modal.showBusy()`
330
+ / `Dialog.showBusy()` all route through the same singleton.
331
+ - **`ModalView` is now a public export** (`src/index.js`,
332
+ `src/lite/index.js`) — use it directly when you need a long-lived
333
+ modal handle (streaming `setContent`, external event wiring,
334
+ subclassing). Most callers should still prefer the static `Modal.*`
335
+ API.
336
+ - **No consumer change required.** The 24 `new Dialog({...})` and
337
+ `Dialog.show*()` sites already in `src/` continue to work via the
338
+ shim. A separate request (`planning/requests/migrate-legacy-dialog-callers.md`)
339
+ tracks the eventual sweep.
340
+ - New docs: `docs/web-mojo/components/ModalView.md`. Updated:
341
+ `components/Modal.md`, `components/Dialog.md` (now a deprecation
342
+ notice + migration table), `README.md`, `docs/agent/architecture.md`.
343
+
344
+ ### Improved — SeriesChart axis labels (nice numbers, formats, rotation)
345
+
346
+ - **Y-axis ticks** now snap to clean `1/2/5 × 10ⁿ` values via the Heckbert
347
+ nice-number algorithm. The "API Metrics" chart and similar `MetricsChart`
348
+ consumers now show `0, 25, 50, 75, 100` instead of `0, 28.77, 57.54,
349
+ 86.31, 115.08, 143.85`. `gridLines` becomes a target count; the algorithm
350
+ picks the closest clean fit.
351
+ - **X-axis labels auto-rotate** `-45°` when they would overlap their slots.
352
+ The chart's bottom padding expands automatically. No configuration
353
+ required; rotation kicks in when labels collide.
354
+ - **`MetricsChart` defaults `xLabelFormat`** based on `granularity`:
355
+ `minutes`/`hours` → `date:'HH:mm'` (`17:00`), `days`/`weeks` → `date:'MMM
356
+ D'` (`Apr 26`), `months` → `date:'MMM YYYY'` (`Apr 2026`). Caller-supplied
357
+ `tooltip.x` still wins. The default is re-applied when `setGranularity()`
358
+ is called.
359
+ - Truncation cap raised from 10 → 24 chars (rotation handles long labels;
360
+ truncation is the fallback for pathological cases like UUIDs).
361
+ - `_formatAxisValue` adds a `B` (billion) branch and step-aware decimal
362
+ precision so very small or very large nice-tick ranges read cleanly.
363
+
364
+ ### Docs — Phase 3 of taxonomy realignment (undocumented public exports)
365
+
366
+ - New doc pages in `docs/web-mojo/`:
367
+ - `core/Router.md` — `Router` class: `?page=` URL handling, `navigate`, route patterns, `route:changed` / `route:notfound` events.
368
+ - `components/ProgressView.md` — file-upload progress UI; `updateProgress`, `markCompleted`, etc.
369
+ - `components/SimpleSearchView.md` — searchable list bound to a `Collection`; emits `item:selected`.
370
+ - `utils/MustacheFormatter.md` — lower-level template renderer behind `View`; `registerFormatter` for custom pipes.
371
+ - `mixins/FileDropMixin.md` — `applyFileDropMixin(ViewClass)` + `enableFileDrop({…})` + `onFileDrop(files, …)`.
372
+ - **Breaking**: `DataWrapper` named export removed from `src/index.js`. Triage found zero consumers (no `src/`, no `examples/`, no `test/` references). The class itself remains in `src/core/utils/MOJOUtils.js`; only the public re-export is gone.
373
+ - README + AGENT cross-links updated to surface the new pages.
374
+
375
+ ### Added — Assistant: `assistant_text` event + chart-option passthrough
376
+
377
+ - **New `assistant_text` WS event** is now handled in `AssistantView`,
378
+ `AssistantPanelView`, and `AssistantContextChat`. When the model writes
379
+ prose alongside tool calls in the same turn, that intermediate text now
380
+ renders as an assistant bubble before the tool-call status indicators.
381
+ `assistant_response` remains the terminal signal that clears the thinking
382
+ indicator and re-enables input. Conversations that don't emit
383
+ `assistant_text` are unchanged.
384
+ - **`AssistantContextChat` gains a small `_adoptConversationId` helper** so
385
+ all three assistant views handle new-conversation events uniformly. The
386
+ adapter remains the canonical owner of `conversationId`.
387
+ - **Chart blocks now forward new `SeriesChart` / `PieChart` options** from
388
+ the LLM into the chart constructor via a strict snake_case → camelCase
389
+ allowlist. New block-level fields: `stacked`, `grouped`, `crosshair_tracking`,
390
+ `cutout`, `show_labels`, `show_percentages`, `colors`, `show_legend`,
391
+ `legend_position`. New per-series fields: `color`, `fill`, `smoothing`.
392
+ Existing minimal chart blocks render identically.
393
+ - Stale doc comment in `AssistantMessageView._renderChartBlock` corrected
394
+ (`MiniPieChart`/`MiniSeriesChart` → `PieChart`/`SeriesChart`).
395
+
396
+ ### Docs — Phase 2 of taxonomy realignment
397
+
398
+ - New doc pages in `docs/web-mojo/`:
399
+ - `extensions/Auth.md` — `mountAuth` + `createAuthClient` (`web-mojo/auth`).
400
+ - `extensions/UserProfile.md` — `UserProfileView`, `PasskeySetupView`, the 11 section views (`web-mojo/user-profile`).
401
+ - `extensions/DocIt.md` — `DocItApp` and the four documentation pages (`web-mojo/docit`).
402
+ - `services/TokenManager.md` — JWT lifecycle, single-flight refresh, the auth gate.
403
+ - `utils/DjangoLookups.md` — `field__lookup` syntax, `LOOKUPS` map, `parseFilterKey`, `formatFilterDisplay`.
404
+ - `utils/ConsoleSilencer.md` — log-level filtering, URL/`localStorage` runtime overrides.
405
+ - `src/extensions/auth/README.md` deleted (the new `extensions/Auth.md` is canonical).
406
+ - `src/extensions/mojo-auth/mojo-auth.js` gets a `LEGACY shim` JSDoc header. No package entry, no internal callers; new code uses `web-mojo/auth`. File is kept for downstream apps still linking it directly.
407
+ - `docs/web-mojo/README.md`, `docs/web-mojo/AGENT.md`, and root `AGENT.md` cross-links updated to surface the new pages.
408
+ - `planning/notes/taxonomy-audit.md` notes that `src/core/utils/TemplateResolver.js` is orphaned (zero consumers, not exported) — tracked for a future cleanup pass.
409
+
410
+ ### Bug fixes — typed alerts now actually render their type
411
+
412
+ - `Dialog.alert(message, title, options)` (and `Modal.alert(...)`) silently
413
+ dropped the second and third arguments — every typed alert rendered as
414
+ `info` regardless of the `type` option. The signature is now correctly
415
+ honored: `Modal.alert('Saved!', 'Done', { type: 'success' })` produces a
416
+ success-styled alert. Object-form (`Modal.alert({ message, title, type })`)
417
+ and single-string form (`Modal.alert('hi')`) continue to work unchanged.
418
+ - `WebApp.showError / showSuccess / showInfo / showWarning` were broken in
419
+ the same way and rendered identically. They now produce visually distinct
420
+ typed alerts and route through `Modal.alert` directly.
421
+ - `WebApp.confirm` also routes through `Modal.confirm` for consistency.
422
+
423
+ ### API direction — Modal is the canonical modal/dialog surface
424
+
425
+ - `Modal.alert / Modal.confirm / Modal.prompt` are now the canonical
426
+ implementations. `Dialog.alert / Dialog.confirm / Dialog.prompt` have been
427
+ rewritten as thin pass-throughs that delegate to Modal — all existing
428
+ `Dialog.*` callers continue to work unchanged, but new code should call
429
+ `Modal.*` directly.
430
+ - `Dialog` itself (the underlying View class) is unchanged: the constructor,
431
+ `Dialog.showDialog / showForm / showModelForm / showCode / showHtmlPreview`,
432
+ z-index management, and `Dialog.showBusy / hideBusy` continue to live there.
433
+ Only the three top-level helpers moved.
434
+ - `docs/web-mojo/components/Modal.md` is now the canonical doc; Dialog.md
435
+ retains its deprecation banner with pass-through notes under each helper.
436
+
437
+ ### UI / CSS — refreshed dialog chrome and typed-alert accents
438
+
439
+ - All dialogs share a refreshed chrome: rounded corners (14px), soft
440
+ drop-shadow, gradient header tint, and a small offset circular close
441
+ button anchored to the top-right corner.
442
+ - Typed alerts (`Modal.alert(... { type })`) now get a 6px colored hero
443
+ band across the top of the modal card and a subtle tinted card background,
444
+ so each type is visually distinct without relying on an icon alone. Color
445
+ tokens: success=`#198754`, error=`#dc3545`, warning=`#ffc107`;
446
+ info/default uses `--mojo-dialog-accent` (see below).
447
+ - New CSS variable `--mojo-dialog-accent`, defined at `:root` and defaulting
448
+ to `var(--bs-primary)`. Drives the header gradient tint and the info-typed
449
+ alert accent. Override at `:root` (or any scope) to set a custom brand
450
+ color without touching `--bs-primary`.
451
+ - Dark-mode rules added under `prefers-color-scheme: dark`, mirroring the
452
+ shape of the existing toast.css dark-mode block.
453
+ - Internal styling hook: typed alerts add `modal-alert modal-alert-{type}`
454
+ to the modal root for downstream apps that want to override the look.
455
+
456
+ ### Breaking — Admin models moved to a separate package entry
457
+
458
+ - 14 admin-coupled `Model` / `Collection` classes have moved out of `src/core/models/`
459
+ into `src/extensions/admin/models/`. The affected models: `AWS`, `Assistant`,
460
+ `Bouncer`, `Email`, `Incident`, `IPSet`, `Job`, `JobRunner`, `LoginEvent`,
461
+ `PublicMessage`, `Push`, `Phonehub`, `ScheduledTask`, `Tickets`.
462
+ - 7 of those (`AWS`, `Email`, `Incident`, `Job`, `JobRunner`, `Push`, `Tickets`)
463
+ were previously re-exported from the main `web-mojo` entry. They are no longer.
464
+ **Migration**: switch to the new `web-mojo/admin-models` entry.
465
+ ```js
466
+ // before
467
+ import { Job, JobList, Incident } from 'web-mojo';
468
+ // after
469
+ import { Job, JobList, Incident } from 'web-mojo/admin-models';
470
+ ```
471
+ - New package entry `web-mojo/admin-models` ships the 14 admin models as **data
472
+ only** — no DOM, Bootstrap, or template deps. Use this entry from a Node
473
+ script, an API client, or any non-portal UI. The `web-mojo/admin` entry
474
+ remains the way to get the admin **pages** (sidebar, dashboards, table pages).
475
+ - `Log` and `ShortLink` stay in `src/core/models/` because they have legitimate
476
+ non-admin consumers (`FileView`'s share-link feature, `user-profile`'s
477
+ activity section). The audit's "admin-only" classification was overzealous on
478
+ those two; their import paths and main-entry export are unchanged.
479
+ - `docs/web-mojo/models/BuiltinModels.md` now covers only the 10 still-core
480
+ models. Admin models documented in `docs/web-mojo/extensions/Admin.md`.
481
+ - 73 internal `@core/models/<X>.js` import statements rewritten to
482
+ `@ext/admin/models/<X>.js` across the 58 admin files that consume them.
483
+
484
+ ### Examples Portal — area-mismatch realignment
485
+
486
+ - `TabView` moved from `extensions/` → `components/` (source has always been at
487
+ `src/core/views/navigation/TabView.js`). Routes change:
488
+ `?page=extensions/tab-view` → `?page=components/tab-view`. Doc moves to
489
+ `docs/web-mojo/components/TabView.md`.
490
+ - `TablePage` doc moved from `components/` → `pages/` (source is at
491
+ `src/core/pages/TablePage.js`). Doc path:
492
+ `docs/web-mojo/pages/TablePage.md`. Example folder unchanged (already at
493
+ `examples/portal/examples/pages/TablePage/`).
494
+ - `FileUpload` moved from `extensions/` → `services/` (source is at
495
+ `src/core/services/FileUpload.js`). Routes change:
496
+ `?page=extensions/file-upload` → `?page=services/file-upload`. Doc moves to
497
+ `docs/web-mojo/services/FileUpload.md`.
498
+ - `docs/web-mojo/extensions/metricsminichartwidget.md` renamed to
499
+ `MetricsMiniChartWidget.md` to match sibling-doc casing.
500
+ - New `FormBuilder` example at
501
+ `examples/portal/examples/forms/FormBuilder/FormBuilderExample.js`. Demos
502
+ `buildFormHTML()` and `buildFieldsHTML()`. `FormBuilder` is now exported
503
+ from the main `web-mojo` entry (was previously only available via
504
+ `@core/forms/FormBuilder.js`).
505
+ - Dead `src/core/views/map/MapView.js` duplicate removed (canonical version
506
+ is `src/extensions/map/MapView.js`, exported via `web-mojo/map`).
507
+ - `docs/web-mojo/forms/FORMS_DOCUMENTATION_PLAN.md` (an internal planning
508
+ doc that snuck into published docs) moved to `planning/notes/`.
509
+
510
+ ### Examples Portal — hub-and-spoke navigation
511
+
512
+ - Replaced the single 75-item sidebar with a hub menu plus four topic
513
+ sub-sidebars: **Architecture**, **Components**, **Forms**, **Extensions**.
514
+ The hub pins a curated **Start Here** path (View, Templates, Model, Page,
515
+ WebApp). Each topic sub-sidebar ends with a "Back to Examples" item that
516
+ returns to the hub, mirroring the existing admin "Exit Admin" pattern.
517
+ - Component variants (Dialog form / context-menu / custom-body, TableView
518
+ batch-actions / custom-row / server-collection, …) now collapse under their
519
+ parent in the sidebar instead of rendering as siblings. Routes are unchanged.
520
+ - `examples.registry.json` now exposes a `topics` tree (each topic → groups →
521
+ items with optional one-level children), and every page record carries
522
+ `topic` and `group` fields. The legacy `menu` array is kept for one cycle.
523
+ - `docs/web-mojo/examples.md` is regenerated under H2/H3 topic/group
524
+ headings and now correctly links each variant row to its own source file.
525
+ - Sidebar widened from the framework default 250px to 300px in this portal
526
+ (set via `--mojo-sidebar-width` CSS variable; framework default unchanged).
527
+ - No framework changes — `Sidebar` already supported multiple registered
528
+ menus, route-driven menu switching, and per-item `handler` callbacks.
529
+
530
+ ### Breaking — Charts extension rebuilt on native SVG
531
+
532
+ - **Chart.js dependency removed.** `BaseChart` previously injected
533
+ `https://cdn.jsdelivr.net/npm/chart.js@4.4.0/dist/chart.umd.js` at runtime;
534
+ that fetch no longer happens. `chart.js` was never in `package.json` and
535
+ remains absent. ~2,400 LOC of source removed: `BaseChart.js` (1,329),
536
+ the old Chart.js-backed `SeriesChart.js` (533), and the old `PieChart.js` (567).
537
+ - **`SeriesChart` rewritten as a native SVG component** (promoted from
538
+ `MiniSeriesChart`). Multi-dataset line/bar/area, click-to-toggle legend,
539
+ hover-isolated highlighting, animated `setData` updates (`animate: false`
540
+ to opt out), built-in 10-color palette + golden-angle HSL fallback, and
541
+ per-series `color` overrides.
542
+ - **Bar charts default to stacked.** `chartType: 'bar'` is stacked unless you
543
+ pass `stacked: false` (or the alias `grouped: true`). `stacked: 'auto'` is
544
+ the default and resolves to `true` for bar, `false` for line/area.
545
+ - **`PieChart` rewritten as a native SVG component** (promoted from
546
+ `MiniPieChart`). Adds slice-edge labels, `chart:click` drill-down, animated
547
+ slice tweens, and an optional `endpoint:` shim that auto-fetches via
548
+ `app.rest.GET` in `onInit`.
549
+ - **`MetricsChart` rewritten on top of native `SeriesChart`.** Public API
550
+ preserved: `endpoint`, `account`, `granularity`, `slugs`, `category`,
551
+ `dateStart`/`dateEnd`, `defaultDateRange`, `quickRanges`, `availableMetrics`,
552
+ `maxDatasets`, `groupRemainingLabel`, `chartType`, `title` (HTML), `height`,
553
+ `yAxis`, `tooltip`, `showDateRange`, `showGranularity`. Methods unchanged:
554
+ `fetchData`, `refresh`, `setGranularity`, `setDateRange`, `setMetrics`,
555
+ `getStats`. Admin call sites (`AdminDashboardPage`, `CloudWatchChart`,
556
+ `ShortLinkView`, `PushDashboardPage`) need no changes.
557
+ - **PNG export moved out of charts into a standalone helper.**
558
+ `MetricsChart.export(format)` removed. Use:
559
+ `import { exportChartPng } from 'web-mojo/charts'; exportChartPng(chart);`
560
+ Works on any view containing an `<svg>`.
561
+ - **`MiniSeriesChart` and `MiniPieChart` exports removed.** The dynamic imports
562
+ in `AssistantMessageView` were updated to `SeriesChart`/`PieChart`. If any
563
+ downstream code imported `MiniSeriesChart`/`MiniPieChart` directly, switch
564
+ to `SeriesChart`/`PieChart`.
565
+ - **Removed at the chart level**: WebSocket integration, `autoRefresh`,
566
+ `setEndpoint`, `setWebSocketUrl`, theme toggle, `chartOptions` passthrough,
567
+ `dataTransform`. Pages own those concerns.
568
+ - New examples portal entries: `SeriesChartExample.js`, `PieChartExample.js`.
569
+ `ChartsExample.js` continues to demo `MiniChart` (the dedicated single-series
570
+ sparkline — kept as-is).
571
+ - `src/charts.js` bumped from 2.1.0 → 3.0.0.
572
+
573
+ ### Added — Charts: floating crosshair tooltip on line charts
574
+
575
+ - **`SeriesChart` gains optional `crosshairTracking` mode** for line/area
576
+ charts. With `crosshairTracking: true`, a transparent rect overlays the
577
+ plot area; on `mousemove` the chart snaps to the nearest column and shows
578
+ a vertical crosshair, a per-dataset ghost dot, and the existing multi-row
579
+ tooltip. Off by default — bar charts ignore the flag.
580
+ - **Bootstrap-theme-aware** — the crosshair line uses
581
+ `var(--bs-secondary-color)` via `currentColor` and auto-adapts under
582
+ `data-bs-theme="dark"`. Pass `crosshairColor` for an explicit override
583
+ (accepts CSS color strings or `var(--…)` references) and `crosshairWidth`
584
+ for a thicker line.
585
+ - **`chart:click` semantics** — in tracking mode, click emits the column
586
+ for the first visible dataset (matches Chart.js `mode: 'index'`). Per-
587
+ dataset clicks remain available with `crosshairTracking: false`.
588
+ - New examples-portal demo card under
589
+ `examples/portal/examples/extensions/Charts/SeriesChartExample.js`.
590
+
5
591
  ### Changed
592
+ - **Examples directory rewritten** — The previous `examples/portal/` (37 pages, 17 templates, ~13k LOC) and all standalone HTML demos have been moved to `examples/legacy/` (with git history preserved). The new `examples/portal/` is a single canonical [`PortalWebApp`](docs/web-mojo/core/PortalWebApp.md) shell whose taxonomy mirrors `docs/web-mojo/`. Each documented component has a folder under `examples/portal/examples/<area>/<Component>/` with a single-file canonical-and-demo `<Component>Example.js` (≤150 LOC, inline template, imports only from `web-mojo`) and an `example.json` manifest. The portal sidebar and route registration are generated by `examples/portal/scripts/build-registry.js` from those manifests, so adding an example never touches `app.js`. Coverage: **59 examples across 8 areas** (`core`, `pages`, `services`, `components`, `extensions`, `forms`, `forms/inputs`, `models`).
593
+ - **`docs/web-mojo/examples.md`** — Generated index of every example file, written by the registry generator. Linked from `docs/web-mojo/README.md`.
594
+ - **Per-doc cross-links** — Each component doc under `docs/web-mojo/` now ends with an `## Examples` section listing the runnable example file(s) for that component. Sections are managed by `examples/portal/scripts/cross-link-docs.js` and bracketed with `<!-- examples:cross-link begin/end -->` markers so reruns are idempotent.
595
+ - **`vite.config.js`** — Added `web-mojo/timeline` and `web-mojo/models` aliases so per-extension package imports resolve in dev.
596
+
597
+ ### Added
598
+ - **`examples/auth/`** — Fresh standalone login flow built on `FormView` + `Rest`, posts to `/login` and redirects to `/examples/portal/` on success. Replaces the old multi-page auth example (now under `examples/legacy/auth/`).
599
+ - **`docs/web-mojo/components/ContextMenu.md`**, **`docs/web-mojo/forms/MultiStepWizard.md`**, **`docs/web-mojo/forms/SearchFilterForms.md`** — Three new doc pages covering components and patterns the legacy portal demonstrated but the docs hadn't.
600
+
601
+ ### Changed (legacy)
6
602
  - **FileView consolidated** — The three overlapping file components (`src/core/views/data/FileView.js` legacy, `src/extensions/admin/storage/FileView.js` admin, and the small `FilePreviewView` chat card) have been reduced to one canonical `FileView` at `src/core/views/data/FileView.js`, exported from both `web-mojo` and `web-mojo/admin`. The new component uses a `SideNavView` layout (Preview / Details / Renditions / Metadata) and drives its Preview section from the backend `category` field (`image`, `video`, `audio`, `pdf`, `document`, `spreadsheet`, `presentation`, `archive`, `other`) — each category gets a purpose-built preview (inline `<video>`/`<audio>`, lightbox gallery, PDF viewer, or download-focused card). `LightboxGallery` and `PDFViewer` are accessed optionally via `window.MOJO.plugins.*` and fall back to `window.open` when the lightbox extension isn't loaded. Metadata section is hidden when empty. `FilePreviewView` (chat attachment card) is unchanged.
7
603
  - **FileView handles async renditions** — The backend now generates renditions asynchronously: `upload_status` flips to `completed` immediately while thumbnails/transcodes run on a background worker. FileView now shows a "Renditions are being generated" placeholder in the Renditions section (with a manual Refresh button) when `File.isRenditionsProcessing()` returns true, and kicks off an automatic background poll (`model.fetch()` every 5s, up to 5 minutes) that stops as soon as the renditions map populates. The poll is cancelled in `onBeforeDestroy`. Preview and Renditions sections listen for `change` on the model and re-render in place as the new URLs arrive, so video posters and rendition rows appear without a manual refresh.
8
604
  - **`File` model helpers** — Added `getCategory()` (with content_type fallback), `hasRenditions()`, `isRenditionsProcessing()`, `getRenditions()`, `getBestImageRendition()`, `getThumbnailUrl()`, and `regenerateRenditions(roles?)` to the `File` model.
package/README.md CHANGED
@@ -131,7 +131,7 @@ Complete authentication system with JWT tokens, login/register forms, and sessio
131
131
  Image and PDF viewers with editing capabilities including cropping and annotation.
132
132
 
133
133
  #### 📊 Charts (`web-mojo/charts`)
134
- Interactive charts built on Chart.js with PieChart, SeriesChart, and more.
134
+ Native SVG charts (SeriesChart, PieChart, MetricsChart) with no Chart.js dependency. `SeriesChart` supports opt-in `crosshairTracking` for floating crosshair + multi-row tooltip on line/area charts. Y-axis ticks snap to clean values via the Heckbert nice-number algorithm; X labels auto-rotate when they overflow their slots. `MetricsChart` defaults `xLabelFormat` from granularity (minutes/hours → `HH:mm`, days/weeks → `MMM D`, months → `MMM YYYY`).
135
135
 
136
136
  #### 📚 Documentation (`web-mojo/docit`)
137
137
  Full-featured documentation portal system with markdown editing and syntax highlighting.
@@ -316,7 +316,7 @@ Our documentation is organized into focused sections — browse online or click
316
316
  - [DataView](https://nativemojo.com/web-mojo/#components/DataView.md) — structured data display
317
317
 
318
318
  ### Extensions
319
- - [Charts](https://nativemojo.com/web-mojo/#extensions/Charts.md) — Chart.js integration (SeriesChart, PieChart)
319
+ - [Charts](https://nativemojo.com/web-mojo/#extensions/Charts.md) — Native SVG charts (SeriesChart, PieChart, MetricsChart)
320
320
  - [Admin](https://nativemojo.com/web-mojo/#extensions/Admin.md) — pre-built admin pages and views
321
321
  - [TabView](https://nativemojo.com/web-mojo/#extensions/TabView.md) — tab navigation
322
322
  - [MapView](https://nativemojo.com/web-mojo/#extensions/MapView.md) / [MapLibreView](https://nativemojo.com/web-mojo/#extensions/MapLibreView.md) — maps