@micha.bigler/ui-core-micha 3.14.3 → 4.0.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 (367) hide show
  1. package/CHANGELOG.md +31 -0
  2. package/README.md +7 -0
  3. package/dist/auth/UserMenu.js +1 -1
  4. package/dist/auth/apiClient.js +7 -6
  5. package/dist/chat/ChatList.js +1 -1
  6. package/dist/chat/ChatThread.js +2 -1
  7. package/dist/chat/ChatWorkspace.js +1 -1
  8. package/dist/chat/ModelPicker.js +2 -5
  9. package/dist/chat/kitSxRegistry.js +9 -0
  10. package/dist/chat/useChatSocket.js +1 -1
  11. package/dist/components/LoginForm.js +1 -1
  12. package/dist/components/SecurityComponent.js +1 -1
  13. package/dist/components/UserListComponent.js +2 -8
  14. package/dist/components/charts/ChartFrame.js +1 -1
  15. package/dist/components/charts/ScatterChart.js +2 -1
  16. package/dist/components/charts/kitSxRegistry.js +6 -0
  17. package/dist/entries/charts.js +6 -0
  18. package/dist/entries/chat.js +8 -0
  19. package/dist/entries/markdown.js +1 -0
  20. package/dist/index.js +0 -14
  21. package/dist/layout/SectionNav.js +1 -1
  22. package/dist/messaging/AttachmentList.js +2 -2
  23. package/dist/messaging/Composer.js +2 -1
  24. package/dist/messaging/ConversationLaunchers.js +1 -4
  25. package/dist/messaging/ConversationList.js +1 -1
  26. package/dist/messaging/DirectMessageLauncher.js +1 -1
  27. package/dist/messaging/MessagingProvider.js +0 -0
  28. package/dist/messaging/PollCard.js +7 -5
  29. package/dist/messaging/ReadTicks.js +2 -2
  30. package/dist/messaging/Thread.js +5 -3
  31. package/dist/notifications/NotificationBell.js +4 -7
  32. package/dist/notifications/NotificationSettings.js +1 -1
  33. package/dist/onboarding/OnboardingProvider.js +3 -6
  34. package/dist/pages/AccountPage.js +1 -2
  35. package/dist/pages/LoginPage.js +2 -3
  36. package/dist/pages/PasswordChangePage.js +2 -3
  37. package/dist/pages/PasswordInvitePage.js +2 -3
  38. package/dist/pages/PasswordResetRequestPage.js +2 -3
  39. package/dist/pages/SignUpPage.js +2 -3
  40. package/dist/pages/SignupConfirmPage.js +2 -3
  41. package/dist/theme/createAppTheme.js +5 -4
  42. package/dist/theme/kitSxEntry.js +11 -0
  43. package/dist/theme/kitSxRegistry.js +2 -15
  44. package/dist/theme/themeCompleteness.js +3 -12
  45. package/dist/utils/auth-errors.js +4 -3
  46. package/package.json +41 -16
  47. package/.github/workflows/publish.yml +0 -126
  48. package/DESIGN.md +0 -60
  49. package/WORK_ORDERS.md +0 -148
  50. package/dev/entries.jsx +0 -721
  51. package/dev/fixtures.js +0 -26
  52. package/dev/main.jsx +0 -75
  53. package/dev/mockTransport.jsx +0 -128
  54. package/docs/CHART-LAYOUT.md +0 -157
  55. package/docs/DARK-TOKENS.md +0 -140
  56. package/docs/TYPE-SCALE.md +0 -111
  57. package/docs/messaging-deviations.md +0 -118
  58. package/index.html +0 -12
  59. package/renovate.json +0 -10
  60. package/scripts/chart-api-census.mjs +0 -415
  61. package/src/auth/AuthContext.jsx +0 -158
  62. package/src/auth/ReauthModal.jsx +0 -82
  63. package/src/auth/UserMenu.jsx +0 -121
  64. package/src/auth/apiClient.jsx +0 -232
  65. package/src/auth/authApi.jsx +0 -539
  66. package/src/auth/authConfig.jsx +0 -34
  67. package/src/auth/reauth.js +0 -47
  68. package/src/chat/ChatComposer.jsx +0 -36
  69. package/src/chat/ChatList.jsx +0 -87
  70. package/src/chat/ChatThread.jsx +0 -128
  71. package/src/chat/ChatWorkspace.jsx +0 -244
  72. package/src/chat/MarkdownReply.jsx +0 -22
  73. package/src/chat/ModelPicker.jsx +0 -85
  74. package/src/chat/api.js +0 -18
  75. package/src/chat/useChatSocket.js +0 -32
  76. package/src/chat/wire.js +0 -7
  77. package/src/components/AccessCodeManager.jsx +0 -288
  78. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  79. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  80. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  81. package/src/components/BulkInviteCsvTab.jsx +0 -198
  82. package/src/components/EmptyState.jsx +0 -38
  83. package/src/components/LoginForm.jsx +0 -159
  84. package/src/components/MFAComponent.jsx +0 -350
  85. package/src/components/MfaLoginComponent.jsx +0 -252
  86. package/src/components/MobileBottomNav.jsx +0 -82
  87. package/src/components/PasskeysComponent.jsx +0 -252
  88. package/src/components/PasswordChangeForm.jsx +0 -87
  89. package/src/components/PasswordResetRequestForm.jsx +0 -43
  90. package/src/components/PasswordSetForm.jsx +0 -97
  91. package/src/components/ProfileComponent.jsx +0 -348
  92. package/src/components/QrSignupManager.jsx +0 -404
  93. package/src/components/QrSignupValidityManager.jsx +0 -106
  94. package/src/components/RegistrationMethodsManager.jsx +0 -150
  95. package/src/components/SecurityComponent.jsx +0 -141
  96. package/src/components/SocialLoginButtons.jsx +0 -83
  97. package/src/components/SoftChip.jsx +0 -93
  98. package/src/components/StatTile.jsx +0 -39
  99. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  100. package/src/components/TurnstileWidget.jsx +0 -99
  101. package/src/components/UserInviteComponent.jsx +0 -76
  102. package/src/components/UserListComponent.jsx +0 -618
  103. package/src/components/charts/BarChart.jsx +0 -102
  104. package/src/components/charts/ChartFrame.jsx +0 -214
  105. package/src/components/charts/LineChart.jsx +0 -126
  106. package/src/components/charts/ScatterChart.jsx +0 -299
  107. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  108. package/src/components/charts/chartDefaults.js +0 -644
  109. package/src/components/charts/chartLabels.js +0 -36
  110. package/src/components/charts/exportChart.js +0 -258
  111. package/src/components/charts/formatters.js +0 -39
  112. package/src/components/charts/palette.js +0 -33
  113. package/src/components/charts/yearTickInterval.js +0 -7
  114. package/src/i18n/authTranslations.ts +0 -2651
  115. package/src/i18n/chartsTranslations.ts +0 -91
  116. package/src/i18n/chatTranslations.ts +0 -55
  117. package/src/i18n/messagingTranslations.ts +0 -120
  118. package/src/i18n/notificationsTranslations.ts +0 -32
  119. package/src/i18n/onboardingTranslations.ts +0 -29
  120. package/src/i18n/sectionNavTranslations.ts +0 -20
  121. package/src/i18n/uiCoreTranslations.js +0 -29
  122. package/src/i18n/userMenuTranslations.ts +0 -5
  123. package/src/index.js +0 -158
  124. package/src/layout/PageLayout.jsx +0 -36
  125. package/src/layout/SectionNav.jsx +0 -320
  126. package/src/messaging/AttachmentList.jsx +0 -145
  127. package/src/messaging/Composer.jsx +0 -197
  128. package/src/messaging/ConversationLaunchers.jsx +0 -51
  129. package/src/messaging/ConversationList.jsx +0 -109
  130. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  131. package/src/messaging/MessageBubble.jsx +0 -183
  132. package/src/messaging/MessagingProvider.jsx +0 -0
  133. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  134. package/src/messaging/PollCard.jsx +0 -163
  135. package/src/messaging/ReactionBar.jsx +0 -43
  136. package/src/messaging/ReadTicks.jsx +0 -82
  137. package/src/messaging/Thread.jsx +0 -195
  138. package/src/messaging/api.js +0 -48
  139. package/src/messaging/composerImageCompression.js +0 -35
  140. package/src/messaging/linkifyText.jsx +0 -37
  141. package/src/notifications/NotificationBell.jsx +0 -84
  142. package/src/notifications/NotificationSettings.jsx +0 -330
  143. package/src/notifications/NotificationsProvider.jsx +0 -224
  144. package/src/notifications/PopupSurface.jsx +0 -105
  145. package/src/notifications/api.js +0 -55
  146. package/src/notifications/feedApi.js +0 -18
  147. package/src/notifications/realtime.jsx +0 -138
  148. package/src/notifications/serviceWorker/sw.js +0 -50
  149. package/src/onboarding/OnboardingProvider.jsx +0 -326
  150. package/src/onboarding/OnboardingWizard.jsx +0 -61
  151. package/src/onboarding/WizardDialogShell.jsx +0 -51
  152. package/src/onboarding/api.js +0 -13
  153. package/src/onboarding/stepSelection.js +0 -16
  154. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  155. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  156. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  157. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  158. package/src/pages/AccountPage.jsx +0 -394
  159. package/src/pages/LoginPage.jsx +0 -343
  160. package/src/pages/PasswordChangePage.jsx +0 -62
  161. package/src/pages/PasswordInvitePage.jsx +0 -177
  162. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  163. package/src/pages/SignUpPage.jsx +0 -268
  164. package/src/pages/SignupConfirmPage.jsx +0 -155
  165. package/src/testing/checkKitIntegration.js +0 -233
  166. package/src/theme/createAppTheme.js +0 -423
  167. package/src/theme/fonts.js +0 -3
  168. package/src/theme/index.js +0 -21
  169. package/src/theme/kitSxRegistry.js +0 -285
  170. package/src/theme/themeCompleteness.js +0 -1045
  171. package/src/theme/tokens.js +0 -478
  172. package/src/utils/auth-errors.js +0 -76
  173. package/src/utils/authService.js +0 -223
  174. package/src/utils/resolveErrorText.js +0 -28
  175. package/src/utils/webauthn.js +0 -51
  176. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  177. package/tests/AccountPage.test.jsx +0 -200
  178. package/tests/AuthContext.test.jsx +0 -129
  179. package/tests/BarChart.test.jsx +0 -112
  180. package/tests/BrowserPushStep.test.jsx +0 -110
  181. package/tests/ChartFrame.test.jsx +0 -336
  182. package/tests/ConversationList.test.jsx +0 -144
  183. package/tests/CookieConsentStep.test.jsx +0 -69
  184. package/tests/EmptyState.test.jsx +0 -62
  185. package/tests/LineChart.test.jsx +0 -80
  186. package/tests/MessagingProvider.test.jsx +0 -50
  187. package/tests/MobileBottomNav.test.jsx +0 -319
  188. package/tests/NotificationBell.test.jsx +0 -60
  189. package/tests/NotificationSettings.test.jsx +0 -276
  190. package/tests/NotificationsProvider.test.jsx +0 -240
  191. package/tests/OnboardingProvider.test.jsx +0 -294
  192. package/tests/OnboardingWizard.test.jsx +0 -143
  193. package/tests/PasswordChangeForm.test.jsx +0 -70
  194. package/tests/PasswordInvitePage.test.jsx +0 -142
  195. package/tests/PasswordSetForm.test.jsx +0 -70
  196. package/tests/PopupSurface.test.jsx +0 -142
  197. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  198. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  199. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  200. package/tests/ScatterChart.test.jsx +0 -270
  201. package/tests/SectionNav.test.jsx +0 -363
  202. package/tests/SignUpPage.test.jsx +0 -208
  203. package/tests/SoftChip.test.jsx +0 -105
  204. package/tests/StatTile.test.jsx +0 -57
  205. package/tests/Thread.test.jsx +0 -151
  206. package/tests/TimeSeriesChart.test.jsx +0 -367
  207. package/tests/UserListComponent.test.jsx +0 -192
  208. package/tests/UserMenu.test.jsx +0 -171
  209. package/tests/apiClientLanguage.test.js +0 -33
  210. package/tests/apiClientPublicPaths.test.js +0 -178
  211. package/tests/authApiLogin.test.js +0 -42
  212. package/tests/authApiRegistration.test.js +0 -31
  213. package/tests/authErrorCodeRendering.test.jsx +0 -77
  214. package/tests/authErrors.test.js +0 -74
  215. package/tests/authTranslations.test.js +0 -74
  216. package/tests/chart-api-census.test.js +0 -366
  217. package/tests/chartAxisTickBand.test.jsx +0 -95
  218. package/tests/chartDefaults.test.js +0 -902
  219. package/tests/chartLabels.test.js +0 -50
  220. package/tests/chartsPalette.test.js +0 -99
  221. package/tests/chatApi.test.js +0 -48
  222. package/tests/chatDriverNames.test.jsx +0 -71
  223. package/tests/chatExports.test.js +0 -3
  224. package/tests/chatList.test.jsx +0 -84
  225. package/tests/chatPicker.test.jsx +0 -82
  226. package/tests/chatSocket.test.jsx +0 -26
  227. package/tests/chatThread.test.jsx +0 -116
  228. package/tests/chatTranslations.test.js +0 -47
  229. package/tests/chatWorkspace.test.jsx +0 -234
  230. package/tests/checkKitIntegration.test.jsx +0 -219
  231. package/tests/createAppTheme.test.js +0 -132
  232. package/tests/createAppThemeDark.test.js +0 -127
  233. package/tests/createAppThemeLightGuard.test.js +0 -40
  234. package/tests/createAppThemePageContrast.test.js +0 -108
  235. package/tests/createAppThemeTypography.test.js +0 -53
  236. package/tests/errorCallSiteGuard.test.js +0 -32
  237. package/tests/exportChart.test.js +0 -313
  238. package/tests/feedApi.test.js +0 -46
  239. package/tests/fixtures/light-theme-baseline.json +0 -2234
  240. package/tests/i18nAggregate.test.js +0 -120
  241. package/tests/i18nGermanVariant.test.js +0 -65
  242. package/tests/loginPageErrorResolution.test.jsx +0 -102
  243. package/tests/messagingApi.test.js +0 -32
  244. package/tests/messagingChunk6.test.jsx +0 -116
  245. package/tests/messagingCompactBubble.test.jsx +0 -64
  246. package/tests/messagingComposer.test.jsx +0 -136
  247. package/tests/messagingComposerChunk5.test.jsx +0 -113
  248. package/tests/messagingContractConformance.test.js +0 -69
  249. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  250. package/tests/messagingExports.test.js +0 -21
  251. package/tests/messagingInteractions.test.jsx +0 -136
  252. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  253. package/tests/messagingLinkify.test.jsx +0 -51
  254. package/tests/messagingMessageActions.test.jsx +0 -163
  255. package/tests/messagingMsg6.test.jsx +0 -105
  256. package/tests/messagingMsg6f.test.jsx +0 -155
  257. package/tests/messagingMsg6g.test.jsx +0 -166
  258. package/tests/messagingMsg6h.test.jsx +0 -136
  259. package/tests/messagingMsg6i.test.jsx +0 -129
  260. package/tests/messagingPollRendering.test.jsx +0 -142
  261. package/tests/messagingReactionMerge.test.jsx +0 -77
  262. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  263. package/tests/messagingThreadReceipts.test.jsx +0 -178
  264. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  265. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  266. package/tests/notificationsApi.test.js +0 -41
  267. package/tests/notificationsExports.test.js +0 -34
  268. package/tests/onboardingDescriptors.test.js +0 -132
  269. package/tests/packageTreeShaking.test.js +0 -126
  270. package/tests/realtime.test.jsx +0 -219
  271. package/tests/resolveErrorText.test.js +0 -72
  272. package/tests/stepSelection.test.js +0 -53
  273. package/tests/themeCompleteness.test.js +0 -626
  274. package/tests/timeSeriesLegend.test.js +0 -99
  275. package/tests/userScreenTranslations.test.jsx +0 -218
  276. package/tsconfig.build.json +0 -18
  277. package/vite.config.mjs +0 -6
  278. package/work-orders/AUTH-1.md +0 -74
  279. package/work-orders/AUTH-2.md +0 -74
  280. package/work-orders/AUTH-4.md +0 -183
  281. package/work-orders/AUTH-5.md +0 -154
  282. package/work-orders/AUTH-7.md +0 -181
  283. package/work-orders/AUTH-8.md +0 -184
  284. package/work-orders/CHART-1.md +0 -285
  285. package/work-orders/CHART-2.md +0 -222
  286. package/work-orders/CHART-3.md +0 -163
  287. package/work-orders/CHART-4.md +0 -203
  288. package/work-orders/CHART-5.md +0 -226
  289. package/work-orders/CHART-6.md +0 -428
  290. package/work-orders/CHART-7.md +0 -175
  291. package/work-orders/DX-1.md +0 -169
  292. package/work-orders/DX-2.md +0 -188
  293. package/work-orders/DX-3.md +0 -195
  294. package/work-orders/I18N-1.md +0 -254
  295. package/work-orders/I18N-3.md +0 -207
  296. package/work-orders/MSG-3.md +0 -375
  297. package/work-orders/MSG-3b.md +0 -1002
  298. package/work-orders/MSG-3c.md +0 -378
  299. package/work-orders/MSG-3d.md +0 -268
  300. package/work-orders/MSG-3e.md +0 -164
  301. package/work-orders/MSG-3f.md +0 -391
  302. package/work-orders/MSG-6e.md +0 -308
  303. package/work-orders/MSG-6f.md +0 -214
  304. package/work-orders/MSG-6g.md +0 -244
  305. package/work-orders/MSG-6h.md +0 -238
  306. package/work-orders/MSG-6i.md +0 -271
  307. package/work-orders/MSG-6j.md +0 -117
  308. package/work-orders/NOTIF-12.md +0 -214
  309. package/work-orders/NOTIF-13.md +0 -142
  310. package/work-orders/NOTIF-14.md +0 -151
  311. package/work-orders/PRIM-1.md +0 -177
  312. package/work-orders/SHELL-1.md +0 -255
  313. package/work-orders/SHELL-2.md +0 -197
  314. package/work-orders/SHELL-3.md +0 -359
  315. package/work-orders/SHELL-4.md +0 -351
  316. package/work-orders/SHELL-5.md +0 -345
  317. package/work-orders/SHELL-6.md +0 -210
  318. package/work-orders/THEME-1.md +0 -587
  319. package/work-orders/THEME-10.md +0 -303
  320. package/work-orders/THEME-11.md +0 -208
  321. package/work-orders/THEME-2.md +0 -339
  322. package/work-orders/THEME-3.md +0 -210
  323. package/work-orders/THEME-4.md +0 -271
  324. package/work-orders/THEME-5.md +0 -341
  325. package/work-orders/THEME-6.md +0 -247
  326. package/work-orders/THEME-7.md +0 -82
  327. package/work-orders/THEME-8.md +0 -211
  328. package/work-orders/THEME-9.md +0 -194
  329. package/work-orders/UCM-AUTH-10.md +0 -490
  330. package/work-orders/UCM-AUTH-11.md +0 -185
  331. package/work-orders/UCM-AUTH-12.md +0 -98
  332. package/work-orders/UCM-AUTH-13.md +0 -47
  333. package/work-orders/UCM-AUTH-9.md +0 -207
  334. package/work-orders/UCM-CHART-10.md +0 -150
  335. package/work-orders/UCM-CHART-11.md +0 -132
  336. package/work-orders/UCM-CHART-12.md +0 -348
  337. package/work-orders/UCM-CHART-13.md +0 -122
  338. package/work-orders/UCM-CHART-14.md +0 -198
  339. package/work-orders/UCM-CHART-15.md +0 -187
  340. package/work-orders/UCM-CHART-16.md +0 -169
  341. package/work-orders/UCM-CHART-17.md +0 -195
  342. package/work-orders/UCM-CHART-18.md +0 -200
  343. package/work-orders/UCM-CHART-8.md +0 -147
  344. package/work-orders/UCM-CHART-9.md +0 -265
  345. package/work-orders/UCM-CHAT-1.md +0 -190
  346. package/work-orders/UCM-CHAT-2.md +0 -75
  347. package/work-orders/UCM-DEP-1.md +0 -63
  348. package/work-orders/UCM-I18N-4.md +0 -226
  349. package/work-orders/UCM-I18N-5.md +0 -211
  350. package/work-orders/UCM-MSG-20.md +0 -192
  351. package/work-orders/UCM-PRIM-2.md +0 -114
  352. package/work-orders/UCM-SHELL-7.md +0 -134
  353. package/work-orders/UCM-SHELL-8.md +0 -125
  354. package/work-orders/UCM-TEST-1.md +0 -304
  355. package/work-orders/UCM-THEME-13.md +0 -69
  356. package/work-orders/UCM-THEME-14.md +0 -312
  357. package/work-orders/UCM-THEME-15.md +0 -356
  358. package/work-orders/UCM-THEME-16.md +0 -80
  359. package/work-orders/UCM-THEME-17.md +0 -111
  360. package/work-orders/UCM-THEME-18.md +0 -184
  361. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  362. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  363. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  364. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  365. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  366. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  367. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,226 +0,0 @@
1
- # WORK ORDER CHART-5 (ui-core-micha) — dual y-axis + always-visible x-axis ticks
2
-
3
- **EXECUTION DIRECTIVE.** If you are the implementer reading this as your own spec, this section is not
4
- addressed to you — it tells the Orchestrator how to invoke you; you ARE that invocation, do not shell
5
- out to `codex exec`. Orchestrator: implement through `codex exec` in the background, invoked **directly
6
- via Bash** (never the `debugger`/`*_coder` Agent wrappers) with **both** flags `--skip-git-repo-check`
7
- and `--dangerously-bypass-approvals-and-sandbox`, prompt passed as a positional argument from this
8
- file. Fall back to direct Claude implementation only on Codex quota / rate-limit / non-zero exit.
9
- **Known at WO authoring time: the Codex workspace is out of credits for this session — the fallback
10
- applies immediately, do not spend time retrying `codex exec` first.**
11
-
12
- Feature WO on `TimeSeriesChart` (CHART-2/3/4). Operator request, found live in jg-ferien's Aktivität
13
- screen: (a) the shared y-axis mixes an integer count series ("Eindeutige Nutzer") with a fractional
14
- hours series ("Anwesenheitszeit"), producing decimal ticks (0.2, 0.4, ...) that don't make sense for a
15
- user count; (b) the x-axis (time buckets) shows **zero** visible tick labels once there are enough
16
- buckets that MUI X-Charts' built-in collision-avoidance decides none of them fit — worse than showing
17
- a sparse subset, this shows nothing at all.
18
-
19
- ## TIER
20
- Tier 2 — shared-core UI, new public surface (a new optional per-series field). Independent `reviewer`
21
- + `ui_reviewer` mandatory.
22
-
23
- ## WHY
24
-
25
- **Y-axis.** CHART-2 deliberately rejected a second y-axis in favor of series toggles ("if you do not
26
- add one, say so deliberately" — CHART-2 said so, choosing toggles). The operator has now explicitly
27
- requested the second y-axis for this exact case, with full awareness of that prior decision (asked
28
- in-chat, chose it knowingly over forcing shared-axis integer ticks — which would make the fractional
29
- series nearly invisible — and over hiding the tick label only when one series is toggled off). This
30
- WO reverses CHART-2's choice on operator authority, it does not silently second-guess it.
31
-
32
- **X-axis.** `node_modules/@mui/x-charts/ChartsXAxis/getVisibleLabels.js`'s default behaviour drops a
33
- tick label the moment it would overlap the previous one (`tickLabelMinGap`) — with many narrow-band
34
- categories (e.g. 24 hourly buckets) and non-trivial label text (jg-ferien's `formatBucketLabel`
35
- produces e.g. `"08/06, 08:00"`), every label can end up colliding and the *entire* axis goes blank.
36
- MUI's own escape hatch is `tickLabelInterval` as a **function** — when provided, it fully replaces the
37
- collision-based filtering (`getVisibleLabels.js`: `if (typeof tickLabelInterval === 'function') return
38
- new Set(xTicks.filter((item, index) => tickLabelInterval(item.value, index)))`), so a deterministic,
39
- evenly-spaced selection can guarantee *some* labels always render regardless of container width or
40
- label length.
41
-
42
- ## SCOPE
43
-
44
- **A. Per-series `axis` field, backward-compatible.** Each entry in `data.series[i]` gains an optional
45
- `axis: 'primary' | 'secondary'` field. Default (omitted, or every series `'primary'`): **byte-for-byte
46
- today's single-shared-axis behaviour** — no `yAxis` array change, no `yAxisKey` on series, nothing
47
- observably different for existing consumers (jg-ferien pre-adoption, or any future host that doesn't
48
- use the field). Only when **at least one** series declares `axis: 'secondary'` does dual-axis mode
49
- activate:
50
- - Build `yAxis` as two entries: primary (`id: 'primary'`, label = existing `yAxisLabel` prop) and
51
- secondary (`id: 'secondary'`, label = new prop `secondaryYAxisLabel`).
52
- - Each series passed to `BarChart` gets `yAxisKey: 'secondary'` when its `axis` is `'secondary'`,
53
- omitted (defaults to the first/primary axis) otherwise — `series` items already pass straight
54
- through `BarChart`'s `...chartProps` to the real `MuiBarChart`, which natively supports
55
- `yAxisKey` per series; no `BarChart.jsx` change needed for this part, verify that during
56
- implementation rather than assuming.
57
- - `secondaryYAxisLabel` is required (throw, matching `BarChart`'s own `xAxisLabel`/`yAxisLabel`
58
- required-prop convention) **only when dual-axis mode is actually active** (i.e. when computing
59
- it: if any series has `axis === 'secondary'` and `secondaryYAxisLabel` is falsy, throw with a
60
- clear message) — do not require it unconditionally, that would break every existing single-axis
61
- caller.
62
-
63
- **B. Auto-detected integer-only ticks per axis group, not a new prop.** For each y-axis actually in
64
- use (primary always; secondary only in dual-axis mode), if **every** data value across that axis's
65
- currently-**visible** series (respecting the existing series-toggle `visibleKeys` state — an axis
66
- whose only integer series just got toggled off should not keep forcing integer ticks on whatever
67
- remains) is a whole number (`Number.isInteger`), apply a `valueFormatter` to that axis's config that
68
- only emits a label for integer tick values and an empty string otherwise (mirrors the X-axis
69
- collision convention: `getVisibleLabels.js` already treats `formattedValue === ''` as "don't show
70
- this tick" for the X axis; verify the Y-axis tick renderer honours the same convention during
71
- implementation — if it does not, use whatever mechanism it actually supports to the same effect, and
72
- say so in the completion note). If not all-integer, leave the axis's default (no custom formatter) —
73
- this is what keeps `Anwesenheitszeit` (fractional hours) unaffected on its own axis, and correctly
74
- does nothing extra for a primary axis that legitimately has fractional data.
75
-
76
- **C. Deterministic x-axis tick visibility.** Replace MUI's default collision-based tick filtering with
77
- an explicit `tickLabelInterval` function on the x-axis config, evenly sampling up to `MAX_X_TICKS`
78
- (pick a sensible constant, e.g. 8) labels across `data.xLabels`, e.g. `index % Math.max(1,
79
- Math.ceil(xLabels.length / MAX_X_TICKS)) === 0` (adjust as needed so the *last* category is also
80
- reachable/considered, not just an artifact of the modulo — check this doesn't systematically drop the
81
- final bucket). This must apply regardless of dual-axis mode (independent scope).
82
-
83
- ## NON-GOALS / DO NOT TOUCH
84
- - No third axis, no per-axis custom colors, no new axis-styling props beyond what SCOPE describes.
85
- - Do not touch the range picker, series-toggle checkboxes' own rendering, `chartsTranslations`, or the
86
- CHART-3/CHART-4 fixes (`visibleKeys` sync, `CHART_HEIGHT`).
87
- - Do not change `BarChart.jsx`/`ChartFrame.jsx` unless SCOPE A's `yAxisKey` passthrough turns out to
88
- need it (verify first, per SCOPE A's own note) — if it does, extend deliberately and say so, matching
89
- CHART-2's own "do not work around a primitive gap in the preset" rule.
90
- - jg-ferien's own adoption (setting `axis: 'secondary'` on `presence_hours`, adding a
91
- `secondaryYAxisLabel`, shortening `formatBucketLabel`) is **explicitly out of scope for this WO** —
92
- a separate companion change in that repo, after this publishes.
93
-
94
- ## RISKS
95
- - `tickLabelInterval` as a function fully bypasses MUI's built-in overlap detection (per SCOPE C's
96
- quoted source) — a fixed `MAX_X_TICKS` could still produce overlapping text at extreme narrow
97
- widths with very long labels. Accepted: "some labels, deterministically" is strictly better than
98
- "zero labels, unpredictably" (today's bug), and host-side label shortening (jg-ferien's future
99
- companion change) is the complementary fix for extreme cases, not this WO's job.
100
- - Every host that adopts `axis: 'secondary'` changes its chart's visual scale contract (two
101
- independent y-domains can visually mislead if not clearly labelled) — mitigated by requiring
102
- `secondaryYAxisLabel`, not by this WO deciding it's always fine.
103
- - The integer-tick auto-detection (SCOPE B) re-evaluates on every toggle (depends on `visibleKeys`) —
104
- confirm this doesn't cause a visible axis-label flicker/jump on toggle beyond the intended "ticks
105
- change because domain changed" behaviour the toggles already produce today.
106
-
107
- ## REQUIRED TESTS TO WRITE
108
- Extend `tests/TimeSeriesChart.test.jsx`. Do NOT run the full suite.
109
-
110
- **Learn from CHART-4's own history in this file (read `WORK_ORDERS.md`'s CHART-4 row before writing
111
- these): an unmocked test asserting real rendered DOM/tick visibility was proven VACUOUS in this exact
112
- component (jsdom's layout/ResizeObserver handling doesn't reproduce real-browser collision behaviour).
113
- Do not repeat that mistake here.** For anything about tick *visibility* or *positions* (SCOPE C, and
114
- SCOPE B's empty-string-for-non-integer-ticks mechanism), assert on the **function/config actually
115
- passed** to the mocked `MuiBarChart` (`chartSpy.mock.calls`) — e.g. call the captured
116
- `tickLabelInterval` function directly with sample `(value, index)` pairs and assert its boolean
117
- results, or call the captured y-axis `valueFormatter` directly with sample tick values and assert its
118
- string output — never assert on rendered pixel positions or DOM overlap in jsdom.
119
-
120
- 1. **Dual-axis backward compatibility**: with no series declaring `axis`, `chartSpy`'s `yAxis` prop
121
- must be unchanged from today's single-entry shape (or however it's currently constructed — assert
122
- equivalently to the existing tests, not a new shape).
123
- 2. **Dual-axis activation**: with one series `axis: 'secondary'`, assert `chartSpy`'s `yAxis` has two
124
- entries (primary/secondary ids, correct labels from `yAxisLabel`/`secondaryYAxisLabel`), and assert
125
- the secondary series' entry in `chartSpy`'s `series` prop carries `yAxisKey` matching the secondary
126
- axis id while the other series' entry does not (or carries the primary id — whichever the
127
- implementation settles on, be explicit and consistent).
128
- 3. **Missing `secondaryYAxisLabel` throws** when a series declares `axis: 'secondary'` but the prop is
129
- absent — mirrors `BarChart`'s own required-prop throw test convention (check
130
- `tests/BarChart.test.jsx` for that pattern).
131
- 4. **Integer-tick auto-detection, both directions**: one case where a y-axis's visible series are all
132
- whole numbers (assert the captured `valueFormatter` returns a non-empty string for an integer tick
133
- value and `''` for a non-integer one), and one case where they are not all whole numbers (assert no
134
- custom `valueFormatter` is applied, or that it returns the value formatted normally for every tick —
135
- whichever the implementation does, assert it explicitly).
136
- 5. **Toggle re-evaluation**: toggling off the one non-integer series on a shared/primary axis (single-
137
- axis mode) changes that axis from "not all-integer" to "all-integer" — assert the formatter
138
- behaviour changes accordingly after the toggle. (This is the SCOPE B "re-evaluates on toggle" case,
139
- RISKS section.)
140
- 6. **X-axis `tickLabelInterval` guarantees coverage**: call the captured function against a large
141
- `xLabels` array (e.g. 24 entries) and assert it returns `true` for at least `N` evenly-spread
142
- indices (pick a concrete, checkable lower bound, e.g. at least 3 for 24 items at `MAX_X_TICKS=8`)
143
- and that it does not return `true` for literally zero indices (the non-vacuity check for the whole
144
- WO — the very bug this section fixes).
145
- 7. **Non-vacuity**: each new test must fail against the current (pre-fix) code — verify before
146
- considering the fix complete. (SCOPE C's test 6 obviously fails today since there is no
147
- `tickLabelInterval` at all; confirm the others similarly.)
148
-
149
- ## TARGET REPO
150
- `C:\Users\biglmi\Documents\webapps\ui-core-micha`. Branch `main`. Publish per the repo's release flow
151
- (minor bump — new optional field/prop, additive, no breaking change to existing callers).
152
-
153
- ## TEST SCOPE FOR THE GATE (orchestrator)
154
- `tests/TimeSeriesChart.test.jsx`. Not the full suite.
155
-
156
- ## CONTEXT PACKAGE — verified current state (Orchestrator, Implementation map)
157
-
158
- Work from this package; do not explore broadly from scratch — open only the named files to verify.
159
-
160
- **File to change: `src/components/charts/TimeSeriesChart.jsx`** — current full return statement and
161
- surrounding derived-state variables (`:117-189`, verified current):
162
- ```jsx
163
- const visibleSeries = seriesConfig.filter((series) => visibleKeys.has(series.key));
164
- const visiblePalette = visibleSeries.map((series) => palette[seriesConfig.indexOf(series) % palette.length]);
165
- const isDataEmpty = seriesConfig.length === 0 || visibleSeries.length === 0;
166
- ...
167
- return (
168
- <ChartFrame ... minHeight={CHART_HEIGHT}>
169
- {!isDataEmpty && (
170
- <BarChart
171
- xAxisLabel={xAxisLabel}
172
- yAxisLabel={yAxisLabel}
173
- xAxis={[{ data: data?.xLabels || [] }]}
174
- series={visibleSeries.map((series) => ({ data: series.data, label: series.label }))}
175
- palette={visiblePalette}
176
- height={CHART_HEIGHT}
177
- />
178
- )}
179
- </ChartFrame>
180
- );
181
- ```
182
- Component signature currently: `{ title, subtitle, xAxisLabel, yAxisLabel, data, loading, error,
183
- onRangeChange, defaultRange }` (`:56-66`) — add `secondaryYAxisLabel` here.
184
-
185
- **`BarChart.jsx`** (full file, unchanged by this WO unless SCOPE A's verification says otherwise):
186
- `series`/`xAxis`/`yAxis` are BarChart's own named props; `series` is passed straight through
187
- (`series={series}` onto `MuiBarChart`, `:35`) with NO per-item transformation — so a `yAxisKey` field
188
- already present on a series object the caller builds should reach `MuiBarChart` unmodified. `yAxis`
189
- goes through `labelledAxis(yAxis, yAxisLabel, {scaleType:'linear'})` (`:37`), which preserves any
190
- `label` already set on an axis entry (only fills in the default when absent) — so `TimeSeriesChart`
191
- passing two fully-labelled `yAxis` entries will not have `BarChart`'s own `yAxisLabel` prop override
192
- them; **`TimeSeriesChart` should stop passing a single top-level `yAxisLabel` to `BarChart` once it is
193
- building its own multi-entry `yAxis` array explicitly** (or `BarChart`'s `yAxisLabel` requirement
194
- throws — check `BarChart.jsx:27-29`'s `if (!xAxisLabel || !yAxisLabel) throw` and account for it:
195
- either keep passing `yAxisLabel` as before, since `labelledAxis` won't clobber pre-labelled entries
196
- anyway, or restructure — pick whichever keeps `BarChart`'s existing required-prop contract intact
197
- without a special case).
198
-
199
- **X-axis**: `xAxis={[{ data: data?.xLabels || [] }]}` (`:181` current) — add `tickLabelInterval` to
200
- this object; `labelledAxis` will preserve it (only fills `label`, spreads everything else through).
201
-
202
- **Existing tests to model conventions on**: `tests/TimeSeriesChart.test.jsx` (chartSpy mock pattern,
203
- already described above) and `tests/BarChart.test.jsx` (required-prop-throws test pattern for the
204
- `secondaryYAxisLabel` throw case).
205
-
206
- ## MINI-HANDOVER (pastable)
207
-
208
- > Repo: `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`).
209
- > Work order: `work-orders/CHART-5.md` — read it fully, then follow the `orchestrate-codex` skill.
210
- > **Codex workspace is out of credits this session — go straight to the direct-Claude fallback.**
211
- >
212
- > Two independent additions to `TimeSeriesChart`, both operator-requested after seeing the shipped
213
- > CHART-2/3/4 chart live: (1) an opt-in second y-axis via a new per-series `axis: 'secondary'` field,
214
- > fully backward-compatible when unused, with auto-detected integer-only tick labels per axis group
215
- > (not a new prop — derived from whether that axis's visible series data is all whole numbers); (2) a
216
- > deterministic x-axis `tickLabelInterval` so time-bucket labels never all vanish under MUI's default
217
- > collision-avoidance, which is exactly what happened live (zero labels shown with 24 hourly buckets).
218
- > **Test-writing pitfall already hit once in this file (CHART-4): do not write a test that asserts on
219
- > real jsdom-rendered tick visibility/position — it will be vacuous. Assert on the captured
220
- > `tickLabelInterval`/`valueFormatter` functions' own return values instead**, calling them directly
221
- > with sample inputs against the mocked `chartSpy` call's props.
222
-
223
- ## PROGRESS CONTRACT
224
- Emit `PLAN: <steps>` up front, then a single-line `PROGRESS: [<n>/<total>] <action>` before every
225
- relevant action and `PROGRESS: [<n>/<total>] done` on completion, spaced so no gap exceeds ~2 min,
226
- stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>`.