@micha.bigler/ui-core-micha 3.14.4 → 4.0.1

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 (341) hide show
  1. package/CHANGELOG.md +29 -0
  2. package/README.md +7 -0
  3. package/dist/chat/kitSxRegistry.js +9 -0
  4. package/dist/components/charts/kitSxRegistry.js +6 -0
  5. package/dist/entries/charts.js +6 -0
  6. package/dist/entries/chat.js +8 -0
  7. package/dist/entries/markdown.js +1 -0
  8. package/dist/index.js +0 -14
  9. package/dist/pages/AccountPage.js +1 -2
  10. package/dist/pages/LoginPage.js +1 -2
  11. package/dist/pages/PasswordChangePage.js +1 -2
  12. package/dist/pages/PasswordInvitePage.js +1 -2
  13. package/dist/pages/PasswordResetRequestPage.js +1 -2
  14. package/dist/pages/SignUpPage.js +1 -2
  15. package/dist/pages/SignupConfirmPage.js +1 -2
  16. package/dist/theme/kitSxEntry.js +11 -0
  17. package/dist/theme/kitSxRegistry.js +2 -15
  18. package/package.json +31 -7
  19. package/.github/workflows/ci.yml +0 -35
  20. package/.github/workflows/publish.yml +0 -126
  21. package/DESIGN.md +0 -60
  22. package/WORK_ORDERS.md +0 -150
  23. package/dev/entries.jsx +0 -721
  24. package/dev/fixtures.js +0 -26
  25. package/dev/main.jsx +0 -75
  26. package/dev/mockTransport.jsx +0 -128
  27. package/docs/CHART-LAYOUT.md +0 -157
  28. package/docs/DARK-TOKENS.md +0 -140
  29. package/docs/TYPE-SCALE.md +0 -111
  30. package/docs/messaging-deviations.md +0 -118
  31. package/index.html +0 -12
  32. package/renovate.json +0 -10
  33. package/scripts/chart-api-census.mjs +0 -415
  34. package/src/auth/AuthContext.jsx +0 -158
  35. package/src/auth/ReauthModal.jsx +0 -82
  36. package/src/auth/UserMenu.jsx +0 -121
  37. package/src/auth/apiClient.jsx +0 -232
  38. package/src/auth/authApi.jsx +0 -539
  39. package/src/auth/authConfig.jsx +0 -34
  40. package/src/auth/reauth.js +0 -47
  41. package/src/chat/ChatComposer.jsx +0 -36
  42. package/src/chat/ChatList.jsx +0 -87
  43. package/src/chat/ChatThread.jsx +0 -128
  44. package/src/chat/ChatWorkspace.jsx +0 -244
  45. package/src/chat/MarkdownReply.jsx +0 -22
  46. package/src/chat/ModelPicker.jsx +0 -85
  47. package/src/chat/api.js +0 -18
  48. package/src/chat/useChatSocket.js +0 -32
  49. package/src/chat/wire.js +0 -7
  50. package/src/components/AccessCodeManager.jsx +0 -288
  51. package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
  52. package/src/components/AllowedEmailDomainsManager.jsx +0 -92
  53. package/src/components/AuthFactorRequirementCard.jsx +0 -95
  54. package/src/components/BulkInviteCsvTab.jsx +0 -198
  55. package/src/components/EmptyState.jsx +0 -38
  56. package/src/components/LoginForm.jsx +0 -159
  57. package/src/components/MFAComponent.jsx +0 -350
  58. package/src/components/MfaLoginComponent.jsx +0 -252
  59. package/src/components/MobileBottomNav.jsx +0 -82
  60. package/src/components/PasskeysComponent.jsx +0 -252
  61. package/src/components/PasswordChangeForm.jsx +0 -87
  62. package/src/components/PasswordResetRequestForm.jsx +0 -43
  63. package/src/components/PasswordSetForm.jsx +0 -97
  64. package/src/components/ProfileComponent.jsx +0 -348
  65. package/src/components/QrSignupManager.jsx +0 -404
  66. package/src/components/QrSignupValidityManager.jsx +0 -106
  67. package/src/components/RegistrationMethodsManager.jsx +0 -150
  68. package/src/components/SecurityComponent.jsx +0 -141
  69. package/src/components/SocialLoginButtons.jsx +0 -83
  70. package/src/components/SoftChip.jsx +0 -93
  71. package/src/components/StatTile.jsx +0 -39
  72. package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
  73. package/src/components/TurnstileWidget.jsx +0 -99
  74. package/src/components/UserInviteComponent.jsx +0 -76
  75. package/src/components/UserListComponent.jsx +0 -618
  76. package/src/components/charts/BarChart.jsx +0 -102
  77. package/src/components/charts/ChartFrame.jsx +0 -214
  78. package/src/components/charts/LineChart.jsx +0 -126
  79. package/src/components/charts/ScatterChart.jsx +0 -299
  80. package/src/components/charts/TimeSeriesChart.jsx +0 -300
  81. package/src/components/charts/chartDefaults.js +0 -644
  82. package/src/components/charts/chartLabels.js +0 -36
  83. package/src/components/charts/exportChart.js +0 -258
  84. package/src/components/charts/formatters.js +0 -39
  85. package/src/components/charts/palette.js +0 -33
  86. package/src/components/charts/yearTickInterval.js +0 -7
  87. package/src/i18n/authTranslations.ts +0 -2651
  88. package/src/i18n/chartsTranslations.ts +0 -91
  89. package/src/i18n/chatTranslations.ts +0 -55
  90. package/src/i18n/messagingTranslations.ts +0 -120
  91. package/src/i18n/notificationsTranslations.ts +0 -32
  92. package/src/i18n/onboardingTranslations.ts +0 -29
  93. package/src/i18n/sectionNavTranslations.ts +0 -20
  94. package/src/i18n/uiCoreTranslations.js +0 -29
  95. package/src/i18n/userMenuTranslations.ts +0 -5
  96. package/src/index.js +0 -158
  97. package/src/layout/PageLayout.jsx +0 -36
  98. package/src/layout/SectionNav.jsx +0 -320
  99. package/src/messaging/AttachmentList.jsx +0 -145
  100. package/src/messaging/Composer.jsx +0 -197
  101. package/src/messaging/ConversationLaunchers.jsx +0 -51
  102. package/src/messaging/ConversationList.jsx +0 -109
  103. package/src/messaging/DirectMessageLauncher.jsx +0 -112
  104. package/src/messaging/MessageBubble.jsx +0 -183
  105. package/src/messaging/MessagingProvider.jsx +0 -0
  106. package/src/messaging/MessagingScopeConfig.jsx +0 -24
  107. package/src/messaging/PollCard.jsx +0 -163
  108. package/src/messaging/ReactionBar.jsx +0 -43
  109. package/src/messaging/ReadTicks.jsx +0 -82
  110. package/src/messaging/Thread.jsx +0 -195
  111. package/src/messaging/api.js +0 -48
  112. package/src/messaging/composerImageCompression.js +0 -35
  113. package/src/messaging/linkifyText.jsx +0 -37
  114. package/src/notifications/NotificationBell.jsx +0 -84
  115. package/src/notifications/NotificationSettings.jsx +0 -330
  116. package/src/notifications/NotificationsProvider.jsx +0 -224
  117. package/src/notifications/PopupSurface.jsx +0 -105
  118. package/src/notifications/api.js +0 -55
  119. package/src/notifications/feedApi.js +0 -18
  120. package/src/notifications/realtime.jsx +0 -138
  121. package/src/notifications/serviceWorker/sw.js +0 -50
  122. package/src/onboarding/OnboardingProvider.jsx +0 -326
  123. package/src/onboarding/OnboardingWizard.jsx +0 -61
  124. package/src/onboarding/WizardDialogShell.jsx +0 -51
  125. package/src/onboarding/api.js +0 -13
  126. package/src/onboarding/stepSelection.js +0 -16
  127. package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
  128. package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
  129. package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
  130. package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
  131. package/src/pages/AccountPage.jsx +0 -394
  132. package/src/pages/LoginPage.jsx +0 -343
  133. package/src/pages/PasswordChangePage.jsx +0 -62
  134. package/src/pages/PasswordInvitePage.jsx +0 -177
  135. package/src/pages/PasswordResetRequestPage.jsx +0 -68
  136. package/src/pages/SignUpPage.jsx +0 -268
  137. package/src/pages/SignupConfirmPage.jsx +0 -155
  138. package/src/testing/checkKitIntegration.js +0 -233
  139. package/src/theme/createAppTheme.js +0 -423
  140. package/src/theme/fonts.js +0 -3
  141. package/src/theme/index.js +0 -21
  142. package/src/theme/kitSxRegistry.js +0 -285
  143. package/src/theme/themeCompleteness.js +0 -1045
  144. package/src/theme/tokens.js +0 -478
  145. package/src/utils/auth-errors.js +0 -76
  146. package/src/utils/authService.js +0 -223
  147. package/src/utils/resolveErrorText.js +0 -28
  148. package/src/utils/webauthn.js +0 -51
  149. package/tests/AccountPage.profileStatements.test.jsx +0 -162
  150. package/tests/AccountPage.test.jsx +0 -200
  151. package/tests/AuthContext.test.jsx +0 -129
  152. package/tests/BarChart.test.jsx +0 -112
  153. package/tests/BrowserPushStep.test.jsx +0 -110
  154. package/tests/ChartFrame.test.jsx +0 -336
  155. package/tests/ConversationList.test.jsx +0 -144
  156. package/tests/CookieConsentStep.test.jsx +0 -69
  157. package/tests/EmptyState.test.jsx +0 -62
  158. package/tests/LineChart.test.jsx +0 -80
  159. package/tests/MessagingProvider.test.jsx +0 -50
  160. package/tests/MobileBottomNav.test.jsx +0 -319
  161. package/tests/NotificationBell.test.jsx +0 -60
  162. package/tests/NotificationSettings.test.jsx +0 -276
  163. package/tests/NotificationsProvider.test.jsx +0 -240
  164. package/tests/OnboardingProvider.test.jsx +0 -294
  165. package/tests/OnboardingWizard.test.jsx +0 -143
  166. package/tests/PasswordChangeForm.test.jsx +0 -70
  167. package/tests/PasswordInvitePage.test.jsx +0 -142
  168. package/tests/PasswordSetForm.test.jsx +0 -70
  169. package/tests/PopupSurface.test.jsx +0 -142
  170. package/tests/ProfileComponent.refresh.test.jsx +0 -194
  171. package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
  172. package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
  173. package/tests/ScatterChart.test.jsx +0 -270
  174. package/tests/SectionNav.test.jsx +0 -363
  175. package/tests/SignUpPage.test.jsx +0 -208
  176. package/tests/SoftChip.test.jsx +0 -105
  177. package/tests/StatTile.test.jsx +0 -57
  178. package/tests/Thread.test.jsx +0 -151
  179. package/tests/TimeSeriesChart.test.jsx +0 -367
  180. package/tests/UserListComponent.test.jsx +0 -192
  181. package/tests/UserMenu.test.jsx +0 -171
  182. package/tests/apiClientLanguage.test.js +0 -33
  183. package/tests/apiClientPublicPaths.test.js +0 -178
  184. package/tests/authApiLogin.test.js +0 -42
  185. package/tests/authApiRegistration.test.js +0 -31
  186. package/tests/authErrorCodeRendering.test.jsx +0 -77
  187. package/tests/authErrors.test.js +0 -74
  188. package/tests/authTranslations.test.js +0 -74
  189. package/tests/chart-api-census.test.js +0 -366
  190. package/tests/chartAxisTickBand.test.jsx +0 -95
  191. package/tests/chartDefaults.test.js +0 -902
  192. package/tests/chartLabels.test.js +0 -50
  193. package/tests/chartsPalette.test.js +0 -99
  194. package/tests/chatApi.test.js +0 -48
  195. package/tests/chatDriverNames.test.jsx +0 -71
  196. package/tests/chatExports.test.js +0 -3
  197. package/tests/chatList.test.jsx +0 -84
  198. package/tests/chatPicker.test.jsx +0 -82
  199. package/tests/chatSocket.test.jsx +0 -26
  200. package/tests/chatThread.test.jsx +0 -116
  201. package/tests/chatTranslations.test.js +0 -47
  202. package/tests/chatWorkspace.test.jsx +0 -234
  203. package/tests/checkKitIntegration.test.jsx +0 -219
  204. package/tests/createAppTheme.test.js +0 -132
  205. package/tests/createAppThemeDark.test.js +0 -127
  206. package/tests/createAppThemeLightGuard.test.js +0 -40
  207. package/tests/createAppThemePageContrast.test.js +0 -108
  208. package/tests/createAppThemeTypography.test.js +0 -53
  209. package/tests/errorCallSiteGuard.test.js +0 -32
  210. package/tests/exportChart.test.js +0 -313
  211. package/tests/feedApi.test.js +0 -46
  212. package/tests/fixtures/light-theme-baseline.json +0 -2234
  213. package/tests/i18nAggregate.test.js +0 -120
  214. package/tests/i18nGermanVariant.test.js +0 -65
  215. package/tests/loginPageErrorResolution.test.jsx +0 -102
  216. package/tests/messagingApi.test.js +0 -32
  217. package/tests/messagingChunk6.test.jsx +0 -116
  218. package/tests/messagingCompactBubble.test.jsx +0 -64
  219. package/tests/messagingComposer.test.jsx +0 -136
  220. package/tests/messagingComposerChunk5.test.jsx +0 -113
  221. package/tests/messagingContractConformance.test.js +0 -69
  222. package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
  223. package/tests/messagingExports.test.js +0 -21
  224. package/tests/messagingInteractions.test.jsx +0 -136
  225. package/tests/messagingLastMessagePreview.test.jsx +0 -93
  226. package/tests/messagingLinkify.test.jsx +0 -51
  227. package/tests/messagingMessageActions.test.jsx +0 -163
  228. package/tests/messagingMsg6.test.jsx +0 -105
  229. package/tests/messagingMsg6f.test.jsx +0 -155
  230. package/tests/messagingMsg6g.test.jsx +0 -166
  231. package/tests/messagingMsg6h.test.jsx +0 -136
  232. package/tests/messagingMsg6i.test.jsx +0 -129
  233. package/tests/messagingPollRendering.test.jsx +0 -142
  234. package/tests/messagingReactionMerge.test.jsx +0 -77
  235. package/tests/messagingReadTicksTooltip.test.jsx +0 -36
  236. package/tests/messagingThreadReceipts.test.jsx +0 -178
  237. package/tests/messagingThreadingQuoting.test.jsx +0 -87
  238. package/tests/messagingUnreadLifecycle.test.jsx +0 -78
  239. package/tests/notificationsApi.test.js +0 -41
  240. package/tests/notificationsExports.test.js +0 -34
  241. package/tests/onboardingDescriptors.test.js +0 -132
  242. package/tests/packageTreeShaking.test.js +0 -126
  243. package/tests/realtime.test.jsx +0 -219
  244. package/tests/resolveErrorText.test.js +0 -72
  245. package/tests/stepSelection.test.js +0 -53
  246. package/tests/themeCompleteness.test.js +0 -626
  247. package/tests/timeSeriesLegend.test.js +0 -99
  248. package/tests/userScreenTranslations.test.jsx +0 -218
  249. package/tsconfig.build.json +0 -18
  250. package/vite.config.mjs +0 -6
  251. package/work-orders/AUTH-1.md +0 -74
  252. package/work-orders/AUTH-2.md +0 -74
  253. package/work-orders/AUTH-4.md +0 -183
  254. package/work-orders/AUTH-5.md +0 -154
  255. package/work-orders/AUTH-7.md +0 -181
  256. package/work-orders/AUTH-8.md +0 -184
  257. package/work-orders/CHART-1.md +0 -285
  258. package/work-orders/CHART-2.md +0 -222
  259. package/work-orders/CHART-3.md +0 -163
  260. package/work-orders/CHART-4.md +0 -203
  261. package/work-orders/CHART-5.md +0 -226
  262. package/work-orders/CHART-6.md +0 -428
  263. package/work-orders/CHART-7.md +0 -175
  264. package/work-orders/DX-1.md +0 -169
  265. package/work-orders/DX-2.md +0 -188
  266. package/work-orders/DX-3.md +0 -195
  267. package/work-orders/I18N-1.md +0 -254
  268. package/work-orders/I18N-3.md +0 -207
  269. package/work-orders/MSG-3.md +0 -375
  270. package/work-orders/MSG-3b.md +0 -1002
  271. package/work-orders/MSG-3c.md +0 -378
  272. package/work-orders/MSG-3d.md +0 -268
  273. package/work-orders/MSG-3e.md +0 -164
  274. package/work-orders/MSG-3f.md +0 -391
  275. package/work-orders/MSG-6e.md +0 -308
  276. package/work-orders/MSG-6f.md +0 -214
  277. package/work-orders/MSG-6g.md +0 -244
  278. package/work-orders/MSG-6h.md +0 -238
  279. package/work-orders/MSG-6i.md +0 -271
  280. package/work-orders/MSG-6j.md +0 -117
  281. package/work-orders/NOTIF-12.md +0 -214
  282. package/work-orders/NOTIF-13.md +0 -142
  283. package/work-orders/NOTIF-14.md +0 -151
  284. package/work-orders/PRIM-1.md +0 -177
  285. package/work-orders/SHELL-1.md +0 -255
  286. package/work-orders/SHELL-2.md +0 -197
  287. package/work-orders/SHELL-3.md +0 -359
  288. package/work-orders/SHELL-4.md +0 -351
  289. package/work-orders/SHELL-5.md +0 -345
  290. package/work-orders/SHELL-6.md +0 -210
  291. package/work-orders/THEME-1.md +0 -587
  292. package/work-orders/THEME-10.md +0 -303
  293. package/work-orders/THEME-11.md +0 -208
  294. package/work-orders/THEME-2.md +0 -339
  295. package/work-orders/THEME-3.md +0 -210
  296. package/work-orders/THEME-4.md +0 -271
  297. package/work-orders/THEME-5.md +0 -341
  298. package/work-orders/THEME-6.md +0 -247
  299. package/work-orders/THEME-7.md +0 -82
  300. package/work-orders/THEME-8.md +0 -211
  301. package/work-orders/THEME-9.md +0 -194
  302. package/work-orders/UCM-AUTH-10.md +0 -490
  303. package/work-orders/UCM-AUTH-11.md +0 -185
  304. package/work-orders/UCM-AUTH-12.md +0 -98
  305. package/work-orders/UCM-AUTH-13.md +0 -47
  306. package/work-orders/UCM-AUTH-9.md +0 -207
  307. package/work-orders/UCM-CHART-10.md +0 -150
  308. package/work-orders/UCM-CHART-11.md +0 -132
  309. package/work-orders/UCM-CHART-12.md +0 -348
  310. package/work-orders/UCM-CHART-13.md +0 -122
  311. package/work-orders/UCM-CHART-14.md +0 -198
  312. package/work-orders/UCM-CHART-15.md +0 -187
  313. package/work-orders/UCM-CHART-16.md +0 -169
  314. package/work-orders/UCM-CHART-17.md +0 -195
  315. package/work-orders/UCM-CHART-18.md +0 -200
  316. package/work-orders/UCM-CHART-8.md +0 -147
  317. package/work-orders/UCM-CHART-9.md +0 -265
  318. package/work-orders/UCM-CHAT-1.md +0 -190
  319. package/work-orders/UCM-CHAT-2.md +0 -75
  320. package/work-orders/UCM-CI-1.md +0 -65
  321. package/work-orders/UCM-DEP-1.md +0 -63
  322. package/work-orders/UCM-I18N-4.md +0 -226
  323. package/work-orders/UCM-I18N-5.md +0 -211
  324. package/work-orders/UCM-MSG-20.md +0 -192
  325. package/work-orders/UCM-PRIM-2.md +0 -114
  326. package/work-orders/UCM-SHELL-7.md +0 -134
  327. package/work-orders/UCM-SHELL-8.md +0 -125
  328. package/work-orders/UCM-TEST-1.md +0 -304
  329. package/work-orders/UCM-THEME-13.md +0 -69
  330. package/work-orders/UCM-THEME-14.md +0 -312
  331. package/work-orders/UCM-THEME-15.md +0 -356
  332. package/work-orders/UCM-THEME-16.md +0 -80
  333. package/work-orders/UCM-THEME-17.md +0 -111
  334. package/work-orders/UCM-THEME-18.md +0 -184
  335. package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
  336. package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
  337. package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
  338. package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
  339. package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
  340. package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
  341. package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
@@ -1,75 +0,0 @@
1
- # UCM-CHAT-2 — Readable driver names in the chat model picker
2
-
3
- Prepared: 2026-10-15. Target repository: `ui-core-micha` (`main`). Correction to `UCM-CHAT-1`, found at acceptance.
4
-
5
- # A. Envelope — addressed to everyone
6
-
7
- ## Goal and expected outcome
8
-
9
- The model picker of the shared chat surface groups its entries by driver. In the UCM-CHAT-1 implementation, each group heading shows the raw driver id the catalogue returns (`claude_cli`, `anthropic_api`, `openai_api`). The prototype `work-orders/assets/UCM-CHAT-1-ai-chat.html` shows readable names instead.
10
-
11
- Expected outcome: the three drivers that `django-core-micha/DCM-CHAT-1` ships appear under readable, translated names, both in the picker and wherever else ui-core-micha shows a driver. An unknown driver id still appears as its raw id, so a driver added later (`django-core-micha/DCM-CHAT-2`) stays usable before it gets a name.
12
-
13
- ## Scope
14
-
15
- - A mapping from the three driver ids to translated names, registered in ui-core-micha's chat translations:
16
-
17
- | Driver id | en | de | fr | sw |
18
- |---|---|---|---|---|
19
- | `claude_cli` | Claude Code subscription | Claude Code (Abo) | Claude Code (abonnement) | Claude Code (usajili) |
20
- | `anthropic_api` | Anthropic API | Anthropic API | API Anthropic | API ya Anthropic |
21
- | `openai_api` | OpenAI API | OpenAI API | API OpenAI | API ya OpenAI |
22
-
23
- - The picker's group heading and the group's accessible name use the translated name.
24
- - Any other place in the chat surface that shows a driver uses the same name. One example is the model-change divider in the thread.
25
- - Unknown driver ids fall back to the raw id.
26
-
27
- ## Copy list (released with this Envelope)
28
-
29
- The twelve names in the table above, verbatim. No other new text.
30
-
31
- ## Non-goals
32
-
33
- - Any change to the catalogue contract or to django-core-micha. The names live in ui-core-micha.
34
- - Other picker behaviour, layout or styling.
35
- - The post-landing re-review of UCM-CHAT-1's last fix batch. That is UCM-CHAT-1's own follow-up.
36
-
37
- ## Tier
38
-
39
- Tier 3: a change inside shared-core. Small and copy-only in effect.
40
-
41
- ## Risks
42
-
43
- - **Id mismatch:** the ids must match exactly what DCM-CHAT-1 returns (`django_core_micha/assistant/catalogue.py`, `DRIVERS`). A mismatch silently falls back to raw ids. The existing picker test fixture uses `openai`, which is not a real driver id.
44
-
45
- ## Required tests to write
46
-
47
- - Picker: groups for `claude_cli`, `anthropic_api` and `openai_api` show their translated names as heading and accessible name. Fixtures use the real driver ids.
48
- - Unknown driver: an entry with an unknown driver id is grouped under its raw id.
49
- - Translations: the three new keys exist in all four languages.
50
-
51
- # B. Implementation map — addressed to the implementer
52
-
53
- ## Context package
54
-
55
- Tier 3 · tests: picker + translations (see Part A). Work from this package; do not explore broadly. Target working directory: `C:/Users/Micha Bigler/Documents/webapps/ui-core-micha` (never the workspace root).
56
-
57
- - `src/chat/ModelPicker.jsx` — `groupByDriver` groups `entries` by `entry.driver`; the group is rendered at about line 38 as `<Box key={driver} role="group" aria-label={driver}>` with `<Typography variant="overline">{driver}</Typography>`. Both the accessible name and the heading must show the translated name. `t` comes from `useTranslation()` already in the file.
58
- - `src/i18n/chatTranslations.ts` — one `chatTranslations` const, entries `'Chat.xxx': { de, en, fr, sw }`. Add exactly three keys, flat like the existing `Chat.effort.low`: `Chat.driver.claude_cli`, `Chat.driver.anthropic_api`, `Chat.driver.openai_api`, with the Envelope's twelve names verbatim (en/de/fr/sw columns). No other new text.
59
- - A small helper keeps the lookup in one place: export `driverName(t, id)` from `src/chat/ModelPicker.jsx` (or a new `src/chat/driverName.js` if cleaner) returning `t(`Chat.driver.${id}`, { defaultValue: id })`, so an unknown id falls back to the raw id with real i18next. Use it in the picker. The thread's model-change divider (`src/chat/ChatThread.jsx`, `selectionLine`) shows only model and effort, no driver; leave it unchanged. No other place in `src/chat/**` renders a driver id (verify with a search for `driver`).
60
- - Tests: `tests/chatPicker.test.jsx` mocks `react-i18next` with `t: (key) => key`; make the mock return `values.defaultValue` when the key starts with `Chat.driver.` and a `defaultValue` is given and the id is not one of the three known ids, and the key otherwise, so every other assertion keeps expecting keys. Update the fixture entries to the real ids `claude_cli`, `anthropic_api` (replace the fake `openai`), keep one extra fixture with an unknown id (for example `mystery_driver`). Assert: group role name and heading text for each known driver equal the translation KEY `Chat.driver.<id>` (the mocked t returns keys); the unknown id group is named by the raw id. Also assert with the REAL `chatTranslations` that the three keys exist with the Envelope's exact English names, and that each key is non-empty in de/en/fr/sw (add to `tests/chatTranslations.test.js`). `tests/chatWorkspace.test.jsx` uses `openai`/`claude_cli` ids in its catalogue fixture and finds the group by name `openai`: update that lookup to the new key-based name.
61
- - Do not edit: `package.json`, lockfile, CHANGELOG, README, `WORK_ORDERS.md`, anything outside `src/chat/**`, `src/i18n/chatTranslations.ts`, `tests/chat*.test.*`. No catalogue contract change.
62
- - Pitfall: the existing aggregate test `tests/i18nAggregate.test.js` iterates all bundle keys; every value needs all four locales as non-empty strings.
63
-
64
- ## Preamble
65
-
66
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source and test files and for running the tests you wrote — nothing else.** Do NOT install dependencies, touch a lockfile, run a package manager, or tidy up stray files; if something in the repo state blocks you, stop and report it as `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT `git add`/`commit`/`push` — leave every change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review). The orchestrator re-runs the authoritative set + does the independent review after you finish — those are the gate; your own run does not count as the gate.
67
- >
68
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final `RESULT: DONE|BLOCKED <reason>`.
69
-
70
-
71
- # C. Orchestrator only — not addressed to the implementer
72
-
73
- > **If this WO was dispatched to you as an implementer: STOP here.**
74
-
75
- Gate #1 open until recorded in the register row. Publish as a patch release; cockpit/CP-CHAT-4 pins the release that contains it.
@@ -1,65 +0,0 @@
1
- # UCM-CI-1 — A dispatch-only CI workflow for ui-core-micha
2
-
3
- Prepared: 2026-10-15. Target repository: `ui-core-micha` (`main`).
4
-
5
- # A. Envelope — addressed to everyone
6
-
7
- ## Goal and expected outcome
8
-
9
- ui-core-micha has one workflow, `publish.yml`, which tests and then publishes on a push to `main`. A change cannot be proven on a candidate ref without publishing, so work such as `UCM-DEP-1` has no safe CI run. This order adds `.github/workflows/ci.yml`: install, build and test on Linux, started only by hand (`workflow_dispatch`), with no publish step and no secrets.
10
-
11
- Expected outcome: `gh workflow run ci.yml -R <owner>/ui-core-micha --ref ci-test/<ID>` runs the same install, build and test steps as `publish.yml` against that ref, and nothing else.
12
-
13
- ## Operator decision this Envelope records (2026-10-15)
14
-
15
- The operator asked for this workflow in session, as the way to verify `UCM-DEP-1`: "Lege für ui-core-micha einen kleinen ci.yml (nur install, build, test, workflow_dispatch) als eigenes Register-Item an und nutze ihn für UCM-DEP-1."
16
-
17
- ## Scope
18
-
19
- - One new file `.github/workflows/ci.yml`:
20
- - trigger: `workflow_dispatch` only;
21
- - `permissions: contents: read`;
22
- - one job on `ubuntu-latest` with the steps of `publish.yml` that precede publishing, using the same action versions and the same Node and pnpm versions as `publish.yml`: checkout, setup-node, setup-pnpm, `pnpm install --frozen-lockfile`, `pnpm run build`, `pnpm run test`;
23
- - no `npm publish`, no `id-token` permission, no secrets, no `registry-url`.
24
- - A register row and the `CI-*` prefix in `WORK_ORDERS.md` (Orchestrator).
25
-
26
- ## Non-goals
27
-
28
- - No change to `publish.yml`, to any test, or to the package.
29
- - No push or pull-request trigger: the workflow runs only when dispatched.
30
- - No matrix, cache tuning or extra jobs.
31
-
32
- ## Tier
33
-
34
- Tier 3: CI. Small in effect.
35
-
36
- ## Risks
37
-
38
- - A `workflow_dispatch` workflow must exist on the default branch before it can be dispatched at a ref; it lands on `main` first and is then used from `ci-test/<ID>` refs.
39
- - The Node and pnpm pins duplicate those of `publish.yml`; `UCM-DEP-1` bumps both.
40
-
41
- ## Required tests to write
42
-
43
- None: the evidence is one dispatched run of the new workflow on a `ci-test/UCM-CI-1` ref.
44
-
45
- # B. Implementation map — addressed to the implementer
46
-
47
- ## Context package
48
-
49
- Work from this package; do not explore broadly. Target working directory: `C:/Users/Micha Bigler/Documents/webapps/ui-core-micha`.
50
-
51
- - Read `.github/workflows/publish.yml` once. Copy, verbatim, the `uses:` pins and versions of its checkout, setup-node (`node-version`) and pnpm/action-setup (`version`) steps. Do not copy the version-check script, the `if:` conditions, the npm update or the publish step.
52
- - Create `.github/workflows/ci.yml`: `name: CI`; `on: workflow_dispatch`; top-level `permissions: contents: read`; one job `test` on `ubuntu-latest` with steps: Check out code, Set up Node, Set up pnpm, Install dependencies (`pnpm install --frozen-lockfile`), Build (`pnpm run build`), Run tests (`pnpm run test`). Same indentation and step-name style as `publish.yml`.
53
- - Do not edit anything else.
54
-
55
- ## Preamble
56
-
57
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source and test files and for running the tests you wrote — nothing else.** Do NOT install dependencies, touch a lockfile, run a package manager, or tidy up stray files; if something in the repo state blocks you, stop and report it as `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT `git add`/`commit`/`push` — leave every change uncommitted in the working tree for the orchestrator's independent review. This order needs no tests; run none. The orchestrator does the independent review and the dispatched run after you finish.
58
- >
59
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final `RESULT: DONE|BLOCKED <reason>`.
60
-
61
- # C. Orchestrator only — not addressed to the implementer
62
-
63
- > **If this WO was dispatched to you as an implementer: STOP here.**
64
-
65
- Gate #1: the operator's instruction of 2026-10-15 in the UCM-CHAT-1/2 Orchestrator session (quoted in Part A). Review lenses per Tier 3 for a workflow file (envelope, regression, duplication, tests do not apply: no tests; sec_reviewer on the permissions block). Evidence: a dispatched run on `ci-test/UCM-CI-1` after the file is on `main`.
@@ -1,63 +0,0 @@
1
- # UCM-DEP-1 — All open Renovate updates in one change on main, one CI run
2
-
3
- Prepared: 2026-10-15. Target repository: `ui-core-micha` (`main`).
4
-
5
- # A. Envelope — addressed to everyone
6
-
7
- ## Goal and expected outcome
8
-
9
- ui-core-micha's eight open Renovate PRs land as one change on `main`, verified by one CI run. A release follows only if a runtime dependency changed; tooling-only updates need none.
10
-
11
- ## Tier
12
-
13
- Tier 3: dependency changes, majors included.
14
-
15
- ## Operator decisions this Envelope records (2026-10-15)
16
-
17
- 1. The bundle contains these open Renovate PRs' updates, in one change on `main`:
18
-
19
- | PR | Update |
20
- |---|---|
21
- | #17 | npm non-major |
22
- | #18 | github-actions |
23
- | #19 | actions/checkout v7 |
24
- | #20 | actions/setup-node v7 |
25
- | #21 | jsdom v30 (test) |
26
- | #22 | pnpm v12 |
27
- | #23 | typescript v7 |
28
- | #24 | vitest v5 (test) |
29
-
30
- 2. A major that needs more than small adaptations (configuration, a renamed import, a test helper) is taken out of the bundle, left as its PR, and reported with the reason. The bundle does not grow into a migration.
31
- 3. Verification is one CI run of the repository's own CI on the candidate (for an app: a `ci-test/<ID>` ref with the full job set). A red job is fixed within decision 2 and the run repeated; not more than that.
32
- 4. After the push Renovate closes the PRs whose update landed; a PR it rebases instead is an update that did not land and is reported.
33
-
34
- ## Scope
35
-
36
- 1. Dependency manifests and lockfiles, workflow `uses:` pins, image pins the updates touch.
37
- 2. The small adaptations decision 2 allows, with tests where behaviour is touched.
38
- 3. Each update's changelog read for breaking changes before it goes in; a breaking change the code meets is adapted (decision 2) or the update is taken out.
39
- 4. A release per the repository's own publish procedure only when the published package's runtime dependencies changed.
40
-
41
- ## Non-goals
42
-
43
- - No new features, no refactoring beyond decision 2.
44
- - No change to the Renovate configuration.
45
- - No pin bump in any consuming app.
46
-
47
- ## Risks
48
-
49
- - pnpm 12 and TypeScript 7 change the build toolchain; the published bundle must stay byte-compatible in its exports. The CI's build and the kit's own tests are the check.
50
-
51
- ## Required tests to write
52
-
53
- None beyond the adaptations of decision 2. The evidence is the CI run of decision 3.
54
-
55
- # B. Implementation map — addressed to the implementer
56
-
57
- *To be filled by the Orchestrator.*
58
-
59
- # C. Orchestrator only — not addressed to the implementer
60
-
61
- > **If this WO was dispatched to you as an implementer: STOP here.**
62
-
63
- Gate #1 open until recorded in the register row. Part of the PR close-out round of 2026-10-15; stagger the CI run with the other bundles of that round (one heavy run at a time on the shared runner). On 2026-10-15 the working tree carried another session's uncommitted changes to `package.json` and `pnpm-lock.yaml` (likely the dcm/ucm chat migration): the same files this bundle changes. Sequence with that session before starting; never fold its changes into this commit.
@@ -1,226 +0,0 @@
1
- # UCM-I18N-4 — Let a consumer choose informal German, and translate the hard-coded English in the auth and user screens
2
-
3
- # A. Envelope — authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- - Goal: an app that addresses its users with "du" gets "du" in every ucm screen, and no ucm screen
8
- shows hard-coded English in a German UI.
9
- - Expected outcome:
10
- - The kit's German strings exist in a formal ("Sie", today's default) and an informal ("du")
11
- variant; a consumer picks one when it registers the kit's strings (the single export from
12
- `I18N-1`). Apps that do nothing keep today's formal German.
13
- - `UserListComponent`, the invite panel (`UserInviteComponent`, `BulkInviteCsvTab`) and their
14
- messages use translation keys for every visible string, in all configured locales.
15
-
16
- ## Context — measured 2026-09-29 in jg-ferien's local browser test (ucm 3.5.0 installed there)
17
-
18
- - jg-ferien addresses its users with "du" throughout; ucm's auth screens use "Sie" — login, signup,
19
- reset request, invite and reset pages (`src/i18n/authTranslations.ts`), so the break runs through
20
- one flow (`/signup` "Sie", jg's `/signup/confirm` "du"), and one page mixes both (invite page
21
- heading "Sie", validation "du").
22
- - Hard-coded English in German UI: `UserListComponent.jsx` — "All Users", "Search",
23
- "Search users...", "Rows per page:", "Successful Login", "Are you sure you want to delete this
24
- user?"; invite panel — "Invite a new user", "Bulk Invite via CSV", "Upload a CSV file containing
25
- email addresses. Header "email" is supported.", "Upload CSV", "Send Invites", success "Invitation
26
- sent.".
27
- - **Operator decision 2026-09-29: generic fixes go to ucm, app-specific ones to the app.**
28
-
29
- ## Scope + non-goals
30
-
31
- - In scope: the variant mechanism at registration time; the informal German variant of the auth
32
- bundle; keys for the hard-coded strings above (de/en/fr at least, plus every locale the bundles
33
- already carry).
34
- - Explicit non-goals / do-not-touch:
35
- - Default behaviour for existing consumers stays formal German — no consumer changes wording
36
- without opting in.
37
- - Behavioural fixes of those screens are `UCM-AUTH-9`.
38
-
39
- ## Tier · gates
40
-
41
- - **Tier 3** — change inside shared-core, a new public option on the registration export.
42
- - Reviewer: `reviewer` (all lenses) · `ui_reviewer`.
43
- - **Done means released and jg-ferien's pin bumped with the option set** (separate jg step).
44
-
45
- ## Risks
46
-
47
- - A variant that only covers some keys silently falls back to "Sie" for the rest; a test must prove
48
- key parity between the two German variants.
49
- - Consumers that already override ucm keys locally must keep working (override order unchanged).
50
-
51
- ## Required tests to WRITE (you write them and run YOUR OWN new ones; the orchestrator's run is the gate)
52
-
53
- 1. Registering with the informal option yields "du" strings for the auth pages; without it, today's
54
- strings.
55
- 2. Key parity: formal and informal German cover the same key set.
56
- 3. `UserListComponent` and the invite panel render no hard-coded English (render in `de`, assert the
57
- listed strings are absent and translated keys present).
58
- 4. Four-locale shape test (`I18N-3`) still passes for the new keys.
59
-
60
- ---
61
-
62
- # B. Implementation map — filled by the Orchestrator — ADDRESSED TO THE IMPLEMENTER
63
-
64
- ## Context package — two independent parts
65
-
66
- ### 1. The variant mechanism + the informal auth bundle
67
-
68
- - **What "registers the kit's strings" means today, concretely** (so the mechanism plugs into the
69
- real thing, not a hypothetical): every consuming app's own `i18n/index.js` imports the named
70
- bundle exports (`authTranslations`, `messagingTranslations`, …) or the single aggregate
71
- `uiCoreTranslations` (`src/i18n/uiCoreTranslations.js`, built by `I18N-1`) and spreads them into
72
- its own i18next `resources` object — see `jg-ferien/frontend/i18n/index.js` for the exact pattern
73
- (not this repo; read it for reference only, do not edit it — jg's own pin-bump/adoption is a
74
- separate step, out of this WO). **No app currently imports `uiCoreTranslations` itself** (checked
75
- — only per-feature bundles are imported today), so changing how the aggregate is BUILT carries no
76
- live migration risk.
77
- - **Do not change `uiCoreTranslations`'s existing shape or behaviour** — `tests/i18nAggregate.test.js`
78
- (`I18N-1`/`I18N-3`) asserts it is byte-identical to the plain merge of the 7 per-feature bundles;
79
- breaking that assertion is not this WO's job. Add a NEW function alongside it instead:
80
- ```js
81
- // src/i18n/uiCoreTranslations.js — ADD this export, keep the existing `uiCoreTranslations` export unchanged
82
- export function createUiCoreTranslations({ germanVariant = 'formal' } = {}) {
83
- return Object.fromEntries(
84
- Object.entries(uiCoreTranslations).map(([key, value]) => {
85
- const { de_informal, ...rest } = value;
86
- if (germanVariant === 'informal' && de_informal) return [key, { ...rest, de: de_informal }];
87
- return [key, rest];
88
- }),
89
- );
90
- }
91
- ```
92
- This is "the single export a consumer picks a variant with" (the Envelope's phrase) — a future jg
93
- adoption step calls `createUiCoreTranslations({ germanVariant: 'informal' })` instead of spreading
94
- `uiCoreTranslations` directly; every OTHER existing consumer is completely unaffected (they don't
95
- call this function at all, and `uiCoreTranslations` itself is untouched) — this is what "no
96
- consumer changes wording without opting in" means mechanically.
97
- - **The informal German variant itself** — add a sibling `de_informal` field to the `de` value of
98
- every key in `src/i18n/authTranslations.ts` where the FORMAL wording actually depends on
99
- Sie/Ihr-form address. Do NOT add `de_informal` to a key whose German text has no such dependency
100
- (e.g. "E-Mail-Adresse", "Passwort", "QR-Token" read identically either way) — the function above
101
- already falls back to the formal `de` value when `de_informal` is absent, so omitting it there is
102
- correct, not incomplete.
103
- - Find every Sie-dependent key with a word-boundary scan of each entry's `de` value against
104
- `\bSie\b|\bIhr\b|\bIhre\b|\bIhrem\b|\bIhren\b|\bIhrer\b|\bIhres\b` (covers "Sie", "Ihr(e/em/en/er/es)"
105
- in all inflected forms) — this repo already has one page that MIXES both forms today
106
- (`Auth.MFA_RECOVERY_TITLE`'s description at `authTranslations.ts` uses "du" while
107
- `Auth.PAGE_INVITE_SUBTITLE` uses "Sie" — measured, not hypothetical), so a plain "does the file
108
- already use du sometimes" check is not sufficient; use the regex scan.
109
- - For each matched key, write a natural informal ("du"/"dein"/"dir"/imperative-du) rewording as
110
- `de_informal`, keeping the same meaning, placeholders (`{{email}}` etc. must appear identically),
111
- and punctuation style as the formal version. This is a real translation task — this is a
112
- shared-core kit that already ships a disclosed machine-translated Swahili bundle (`I18N-3`); do
113
- the same here: **disclose in your final `RESULT:` line that the informal wording was machine-
114
- translated by you (the implementing model), not reviewed by a fluent German speaker**, exactly
115
- as `I18N-3` did for Swahili. Do not silently imply human review.
116
- - **Test file:** extend `tests/i18nAggregate.test.js` (it already imports `uiCoreTranslations` and
117
- the per-bundle exports — read it first) or add a new `tests/i18nGermanVariant.test.js`, covering:
118
- 1. For a representative key (e.g. `Auth.PAGE_INVITE_SUBTITLE`),
119
- `createUiCoreTranslations({ germanVariant: 'informal' }).['Auth.PAGE_INVITE_SUBTITLE'].de`
120
- is the informal wording and does NOT match the Sie-form regex; the default call
121
- (`createUiCoreTranslations()`, no argument) returns the SAME `de` value as plain
122
- `uiCoreTranslations['Auth.PAGE_INVITE_SUBTITLE'].de` (today's formal string, unopted-in
123
- consumers see no change).
124
- 2. **The real parity guard the Risk note asks for:** scan `authTranslations` for every key whose
125
- `de` matches the Sie-form regex above, and assert EACH such key has a non-empty `de_informal`
126
- that does NOT itself match the Sie-form regex (proves it was actually rewritten, not copied).
127
- This is the test that would fail if a future key were added with formal wording only and
128
- forgotten — the actual failure mode the Envelope's Risk names, not a generic "same key set"
129
- check (which would be trivially true by construction here and prove nothing).
130
- 3. Four-locale shape test (`I18N-3`, `tests/i18nAggregate.test.js`'s existing
131
- `REQUIRED_LOCALES = ['de','en','fr','sw']` check) still passes — it iterates `uiCoreTranslations`
132
- itself, which is unchanged; run it to confirm, do not edit it.
133
- 4. Existing consumers unaffected: `uiCoreTranslations['Auth.PAGE_INVITE_SUBTITLE']` (the plain,
134
- unchanged export) still equals exactly what it did before this WO — read from
135
- `authTranslations.ts` directly, minus the new `de_informal` field which existing code never
136
- reads.
137
-
138
- ### 2. Hard-coded English in `UserListComponent`, `UserInviteComponent`, `BulkInviteCsvTab`
139
-
140
- - **Every string named in the Envelope's Context already uses `t(key, englishDefault)`** — the
141
- translation KEYS are already referenced in the JSX, they are simply missing from every bundle, so
142
- `t()` silently falls through to the English default regardless of locale. **In almost every case
143
- the fix is adding the bundle entry, not touching the component.** Add these keys to
144
- `src/i18n/authTranslations.ts` (all four locales it already carries: de/en/fr/sw — plain, correct
145
- translations, NOT the informal-German mechanism from part 1, this is unrelated hard-coded-string
146
- work):
147
- - From `src/components/UserListComponent.jsx` (verified against the file, line refs current):
148
- `UserList.DELETE_CONFIRM` (`:93`), `Common.OPERATION_FAILED` (`:278`), `UserList.NEW` (`:313`),
149
- `UserList.SUCCESSFUL_LOGIN` (`:331`), `UserList.ROLE` (`:349`), `Common.ACTIONS` (`:398`),
150
- `UserList.TITLE` (`:503`), `Common.SEARCH` (`:509`), `UserList.SEARCH_PLACEHOLDER` (`:510`),
151
- `UserList.NO_USERS` (`:560`). (`Common.YES`/`Common.NO`/`Common.DELETE`/`Auth.EMAIL_LABEL`/
152
- `Profile.NAME_LABEL` already exist — do not re-add them.)
153
- - **One genuine code change, not just a bundle entry:** the `<TablePagination>` at `:581` has no
154
- localisation props at all — MUI supplies its own English default "Rows per page:" directly, it
155
- is not reachable via `t()` today. Add `labelRowsPerPage={t('UserList.ROWS_PER_PAGE', 'Rows per
156
- page:')}` to that element, plus the new `UserList.ROWS_PER_PAGE` bundle entry.
157
- - From `src/components/UserInviteComponent.jsx`: `Auth.INVITE_SENT_SUCCESS` (`:29`, `:104` in
158
- `BulkInviteCsvTab.jsx` too — shared key), `Auth.INVITE_TITLE` (`:43`). (`Auth.EMAIL_LABEL`,
159
- `Auth.INVITE_BUTTON` already exist.)
160
- - From `src/components/BulkInviteCsvTab.jsx`: `Account.BULK_INVITE_NO_EMAILS` (`:82`),
161
- `Account.BULK_INVITE_PARSE_FAILED` (`:87`), `Account.BULK_INVITE_DONE` (`:117`, has `{{ok}}`/
162
- `{{total}}` interpolation — keep both placeholders in every locale), `Account.BULK_INVITE_TITLE`
163
- (`:129`), `Account.BULK_INVITE_HINT` (`:132-135`, multi-line `t()` call — easy to miss with a
164
- single-line grep, it IS in scope), `Account.BULK_INVITE_UPLOAD` (`:143`),
165
- `Account.BULK_INVITE_SEND` (`:147`), `Account.BULK_INVITE_COUNT` (`:150`, `{{count}}`),
166
- `Common.STATUS` (`:166`), `Common.DETAILS` (`:167`), `Account.BULK_INVITE_PROGRESS` (`:190`,
167
- `{{done}}`/`{{total}}`), `Account.BULK_INVITE_SUCCESS_COUNT` (`:192`, `{{count}}`).
168
- (`Auth.EMAIL_LABEL`, `Common.SUCCESS`, `Common.ERROR` already exist.)
169
- - **`UCM-AUTH-9` already landed** (earlier in this release's sequence) and touched this SAME
170
- file: it added `UserList.ROLE_UPDATE_SUCCESS` (already present, all four locales — do not
171
- re-add it) and, after its own review, reused the pre-existing `Auth.SELF_SIGNUP_DISABLED` key
172
- for the closed-signup message rather than adding a new `Auth.SIGNUP_CLOSED` key (that key does
173
- NOT exist — do not look for it or add it).
174
- - Test file: extend `tests/UserListComponent`/`UserInviteComponent`/`BulkInviteCsvTab` tests if they
175
- exist (grep `tests/`), or add focused new ones:
176
- 1. Render each of the three components with `i18n.language = 'de'` (or however this repo's test
177
- harness sets locale — check an existing test that asserts translated text, e.g.
178
- `tests/authTranslations.test.js`, for the pattern) and assert NONE of the literal English
179
- default strings listed above are present, and the translated (German) text IS present.
180
- 2. Four-locale shape test (`i18nAggregate.test.js`) still passes for every new key.
181
-
182
- ## Do-not-touch / invariants
183
-
184
- - Default behaviour for existing consumers stays formal German — `uiCoreTranslations` itself must
185
- not change; only the new `createUiCoreTranslations` function is variant-aware.
186
- - Behavioural fixes of the auth screens are `UCM-AUTH-9`'s scope, not this one — this WO only adds
187
- strings/keys and the variant mechanism, it does not change component logic (aside from the one
188
- named `labelRowsPerPage` prop addition, which is not a behaviour change).
189
- - No secrets, no dependency changes — everything here is data (translation bundles) plus one small
190
- pure function.
191
-
192
- ## Target repo working directory (absolute)
193
-
194
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`)
195
-
196
- ## Preamble — a REQUIRED block IN this file, not something appended at invocation
197
-
198
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
199
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
200
- > app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
201
- > unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register
202
- > row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source
203
- > and test files and for running the tests you wrote — nothing else.** Do NOT install dependencies,
204
- > touch a lockfile, run a package manager, or tidy up stray files; if something in the repo state
205
- > blocks you, stop and report it as `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT
206
- > `git add`/`commit`/`push` — leave every
207
- > change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
208
- > the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
209
- > and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
210
- > The orchestrator re-runs the authoritative set + does the independent review after you finish —
211
- > those are the gate; your own run does not count as the gate.
212
- >
213
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
214
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
215
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
216
- > `RESULT: DONE|BLOCKED <reason>`.
217
-
218
- ---
219
-
220
- # C. Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
221
-
222
- > **If you are the implementer reading this work order as your own specification: STOP at this line.
223
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it — no
224
- > reviewers, no verification run, no register edit, no commit.**
225
-
226
- *(to be filled by the Orchestrator: execution directive; `reviewer` (all lenses) + `ui_reviewer`; release; jg-ferien pin bump with the informal option; register rows here and in jg (`JG-UX-10`).)*
@@ -1,211 +0,0 @@
1
- # UCM-I18N-5 — User-list pagination range text is hard-coded English
2
-
3
- # A. Envelope — authored by the Expertenchat
4
-
5
- ## Goal & expected outcome
6
-
7
- - Goal: the user list's pagination reads in the user's language.
8
- - Expected outcome: `UserListComponent`'s `TablePagination` renders its "1–4 of 4" text through a
9
- translation key (de/en/fr and every locale the bundles carry), the way `labelRowsPerPage`
10
- already does.
11
-
12
- ## Context — measured 2026-10-01 in jg-ferien's local browser (ucm 3.7.0 installed there)
13
-
14
- - `/account?tab=users` in German: "Zeilen pro Seite: 25 ▾ · **1–4 of 4**". `UserListComponent.jsx`
15
- (~l.589-600) sets `labelRowsPerPage={t('UserList.ROWS_PER_PAGE', …)}` but no
16
- `labelDisplayedRows`, so MUI's English default renders. It is the only `TablePagination` in ucm.
17
- - Follows `UCM-I18N-4` (hard-coded English in the user list).
18
-
19
- ## Scope + non-goals
20
-
21
- - In scope: `labelDisplayedRows` via a key with count interpolation; tests; release.
22
- - Explicit non-goals / do-not-touch: no other change to the user list.
23
-
24
- ## Tier · gates
25
-
26
- - **Tier 3** — change inside shared-core (small).
27
- - Done means released AND jg-ferien's pin bumped.
28
-
29
- ## Risks
30
-
31
- - The "more than" form (`count === -1`) must have a wording too, or it renders "of -1".
32
-
33
- ## Required tests to WRITE (you write them and run YOUR OWN new ones; the orchestrator's run is the gate)
34
-
35
- 1. In `de`, the pagination shows the German range text; in `en` the English one.
36
- 2. Key-parity: every locale bundle has the new key.
37
-
38
- ---
39
-
40
- # B. Implementation map — filled by the Orchestrator — ADDRESSED TO THE IMPLEMENTER
41
-
42
- ## Context package
43
-
44
- ### The call site
45
-
46
- `src/components/UserListComponent.jsx:589-601`:
47
- ```jsx
48
- <TablePagination
49
- component="div"
50
- count={sortedUsers.length}
51
- page={page}
52
- onPageChange={(_, newPage) => setPage(newPage)}
53
- rowsPerPage={pageSize}
54
- onRowsPerPageChange={(event) => {
55
- setPageSize(Number(event.target.value));
56
- setPage(0);
57
- }}
58
- labelRowsPerPage={t('UserList.ROWS_PER_PAGE', 'Rows per page:')}
59
- rowsPerPageOptions={[10, 25, 50, 100]}
60
- />
61
- ```
62
- `t`/`i18n` come from `useTranslation()` (`react-i18next`), already in scope at l.53.
63
-
64
- ### MUI's `labelDisplayedRows` contract
65
-
66
- MUI's own default (`node_modules/@mui/material/TablePagination/TablePagination.js:119-124`,
67
- for reference only — do not import it):
68
- ```js
69
- function defaultLabelDisplayedRows({ from, to, count }) {
70
- return `${from}–${to} of ${count !== -1 ? count : `more than ${to}`}`;
71
- }
72
- ```
73
- The prop signature is `({ from, to, count, page }) => ReactNode`. `count` is `-1` when the total
74
- is unknown/unbounded — this component always passes a real `sortedUsers.length`, but the prop
75
- contract still has to handle `-1` defensively (the Risk note): MUI itself would call the function
76
- with `-1` only if `count={-1}` were passed, which this component doesn't do — handle it anyway
77
- since the function must satisfy the full contract, not just this component's current call site.
78
-
79
- ### The translation bundle has FOUR locales, not three
80
-
81
- `src/i18n/authTranslations.ts` (flat `export const authTranslations = { "Key.NAME": { de, fr, en,
82
- sw }, ... }`) carries `de`/`fr`/`en`/`sw` for every existing key, confirmed by grepping all locale
83
- codes in the file — **sw (Swahili) is real and already translated throughout, not a stub**. "every
84
- locale the bundles carry" in the Envelope means these four, not jg-ferien's usual three. Add the
85
- new key(s) in the same shape, next to `UserList.ROWS_PER_PAGE` (~l.2050-2055) for locality.
86
-
87
- Proposed keys (interpolated, i18next `{{var}}` syntax — do not reserialize the whole file through
88
- `JSON.parse`/`JSON.stringify`, this is a `.ts` module, not JSON; a plain text insert keeps every
89
- other entry byte-identical):
90
- ```ts
91
- "UserList.DISPLAYED_ROWS": {
92
- "de": "{{from}}–{{to}} von {{count}}",
93
- "fr": "{{from}}–{{to}} sur {{count}}",
94
- "en": "{{from}}–{{to}} of {{count}}",
95
- "sw": "{{from}}–{{to}} ya {{count}}"
96
- },
97
- "UserList.DISPLAYED_ROWS_MORE_THAN": {
98
- "de": "{{from}}–{{to}} von mehr als {{to}}",
99
- "fr": "{{from}}–{{to}} sur plus de {{to}}",
100
- "en": "{{from}}–{{to}} of more than {{to}}",
101
- "sw": "{{from}}–{{to}} ya zaidi ya {{to}}"
102
- }
103
- ```
104
- The `sw` wording reuses "ya" for "of"/possessive, already used this way elsewhere in the same file
105
- (e.g. l.57 `"ruhusa ya kutuma mialiko"`, l.114 `"barua pepe ya kuweka upya"`) and "zaidi ya" ("more
106
- than") as a plain compositional phrase — a reasonable best-effort construction, NOT a
107
- native-speaker-verified translation; say so plainly in your own report rather than presenting it as
108
- settled, same as you would for any other claim you can't independently verify.
109
-
110
- Call site becomes:
111
- ```jsx
112
- labelDisplayedRows={({ from, to, count }) =>
113
- count === -1
114
- ? t('UserList.DISPLAYED_ROWS_MORE_THAN', '{{from}}–{{to}} of more than {{to}}', { from, to })
115
- : t('UserList.DISPLAYED_ROWS', '{{from}}–{{to}} of {{count}}', { from, to, count })
116
- }
117
- ```
118
-
119
- ### Existing test harness to extend, not duplicate
120
-
121
- `tests/userScreenTranslations.test.jsx` already renders `UserListComponent` through a REAL
122
- `i18next` instance pinned to German (`withGermanI18n`, ~l.22-30, built from
123
- `authTranslations.*.de`) and asserts rendered German strings plus `expectNoEnglishDefaults()`
124
- (~l.34-39, checks `document.body.textContent` against an `ENGLISH_DEFAULTS` list, ~l.33-46). The
125
- test `'renders UserListComponent in German, including pagination and action feedback'` (~l.97-125)
126
- already fetches exactly 1 user, so the pagination currently renders English "1–1 of 1" — add that
127
- literal string (or your chosen German text) to the existing `for (const german of [...])` loop
128
- (~l.115) to assert the real rendered pagination text, and add the English range phrasing (e.g.
129
- `'of 1'` or similar, whatever actually changes) to `ENGLISH_DEFAULTS` so `expectNoEnglishDefaults()`
130
- (already called at line 124) starts actually catching a regression here — today it does NOT, since
131
- no "of N" string is in that list, which is why this bug shipped unnoticed.
132
-
133
- Required test 1 (German vs English) is naturally satisfied by extending this file: German via the
134
- existing `withGermanI18n` harness, English via a parallel small i18next instance (or reuse the
135
- `en` resources the same way `germanResources` is built from `.de`) rendering the same component and
136
- asserting the English range text.
137
-
138
- Required test 2 (key-parity across all four locales) — check whether a generic "every key has
139
- every locale" structural test already exists in this repo (grep `authTranslations` test files for
140
- something like `Object.values(...).every(...)` or a locale-set check) before writing a new one;
141
- extend it if so, add a small standalone one for just these two new keys if not.
142
-
143
- ## Target repo working directory (absolute)
144
-
145
- `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`)
146
-
147
- ## Preamble — a REQUIRED block IN this file, not something appended at invocation
148
-
149
- > The text above is the COMPLETE spec — the committed WO file's content, not a plan to refine; there
150
- > is no separate plan file. Read the nearest `AGENTS.md`, the relevant `.codex/skills/<role>/SKILL.md`, and the
151
- > app `MEMORY.md` ONLY for conventions. Stay in scope; do not touch auth/permissions/deps/schema/CI
152
- > unless the spec says so; do not update `MEMORY.md`. **Do NOT edit `WORK_ORDERS.md` — the register
153
- > row and the review verdicts are the orchestrator's alone.** **Your tools are for editing source
154
- > and test files and for running the tests you wrote — nothing else.** Do NOT install dependencies,
155
- > touch a lockfile, run a package manager, or tidy up stray files; if something in the repo state
156
- > blocks you, stop and report it as `RESULT: BLOCKED <reason>` instead of fixing it. Do NOT
157
- > `git add`/`commit`/`push` — leave every
158
- > change uncommitted in the working tree for the orchestrator's independent review. WRITE the tests
159
- > the `Required tests` section calls for AND **RUN the tests you just wrote** to confirm they execute
160
- > and pass — that is the ONLY test run you do (NOT the app's affected/full suite, NOT any review).
161
- > The orchestrator re-runs the authoritative set + does the independent review after you finish —
162
- > those are the gate; your own run does not count as the gate.
163
- >
164
- > Narrate continuously: a `PLAN: <step1> | <step2> | …` line up front, then a single-line
165
- > `PROGRESS: [<n>/<total>] <present-tense action>` before every relevant action (and `… done` on
166
- > completion), spaced so no gap exceeds ~2 min, stdout unbuffered, plus exactly one final
167
- > `RESULT: DONE|BLOCKED <reason>`.
168
-
169
- ---
170
-
171
- # C. Orchestrator only — NOT ADDRESSED TO THE IMPLEMENTER
172
-
173
- > **If you are the implementer reading this work order as your own specification: STOP at this line.
174
- > Everything below describes what the Orchestrator does AFTER you finish. You do none of it — no
175
- > reviewers, no verification run, no register edit, no commit.**
176
-
177
- **Execution directive:** dispatch via `codex exec --skip-git-repo-check
178
- --dangerously-bypass-approvals-and-sandbox -m gpt-5.6-luna - < work-orders/UCM-I18N-5.md` (today,
179
- 2026-10-02, already recorded `available` in `webapps/.claude/codex-status.md`), cwd =
180
- `C:\Users\biglmi\Documents\webapps\ui-core-micha`. Monitor for `RESULT: DONE|BLOCKED`.
181
-
182
- **Review routing:** Tier 3 (shared-core) — full `reviewer` lens set (`envelope`, `regression`,
183
- `duplication`, `tests`, codex/gpt-5.6-luna, one concurrent batch, diff inline) PLUS `ui_reviewer`
184
- (frontend-adjacent: a rendered component's i18n text). `duplication` should specifically check
185
- whether any OTHER app already patched around this same MUI default locally (a local workaround that
186
- this shared-core fix should make redundant, worth naming even if out of this WO's scope to remove).
187
-
188
- **Tests:** the Orchestrator re-runs `tests/userScreenTranslations.test.jsx` (and any new/renamed
189
- key-parity test file) as the gate — not ucm's full suite (Tier 3 but a small, local-only change;
190
- no cross-app ripple to justify a full run per `AGENTS.md` → Test scope).
191
-
192
- **Release:** patch bump (3.11.0 → 3.11.1) — this extends `UCM-I18N-4`'s existing i18n-gap category
193
- in the same component, not a new capability area, per the project convention (version bump reflects
194
- scope, not mere newness). Update `package.json` + `CHANGELOG.md`, then the repo's normal publish
195
- path (check `.github/workflows/` or `package.json` scripts for how a previous release like
196
- `UCM-THEME-14`/3.11.0 or `UCM-AUTH-11`/3.9.1 actually published, don't assume `npm publish` by
197
- hand — follow the established mechanism).
198
-
199
- **jg-ferien pin bump:** after the release is live, bump `ui-core-micha`'s pin in
200
- `jg-ferien/frontend/package.json`, install, run jg-ferien's own affected tests (anything touching
201
- `UserListComponent` consumption, if jg-ferien renders it at all — check first; if jg-ferien doesn't
202
- use `UserListComponent`, the pin bump itself plus jg-ferien's existing suite staying green is the
203
- evidence), commit + push to jg-ferien's `develop`.
204
-
205
- **Register:** `done` only once BOTH halves land — the release AND the jg-ferien pin bump (the WO's
206
- own Tier line: "Done means released AND jg-ferien's pin bumped"). Row here (ui-core-micha's
207
- `WORK_ORDERS.md`) AND a row in jg-ferien's own `WORK_ORDERS.md` noting the pin bump, per the
208
- Envelope's own closing instruction.
209
-
210
- **Commit:** ui-core-micha lands on `main` (no `develop` branch here, confirmed in `AGENTS.md`'s
211
- branch table). jg-ferien's pin bump lands on `develop` as usual.