@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,99 +0,0 @@
1
- // @vitest-environment jsdom
2
- import React from 'react';
3
- import i18next from 'i18next';
4
- import { afterEach, describe, expect, it, vi } from 'vitest';
5
- import { cleanup, render, screen } from '@testing-library/react';
6
- import { I18nextProvider } from 'react-i18next';
7
- import { ThemeProvider, createTheme } from '@mui/material/styles';
8
-
9
- const chartSpy = vi.hoisted(() => vi.fn(() => null));
10
- vi.mock('@mui/x-charts/BarChart', () => ({ BarChart: chartSpy }));
11
-
12
- import { TimeSeriesChart } from '../src/components/charts/TimeSeriesChart';
13
-
14
- chartSpy.mockImplementation((props) => React.createElement(
15
- 'div',
16
- { 'data-testid': 'mui-bar-chart' },
17
- !props.hideLegend
18
- ? React.createElement('div', { 'data-testid': 'mui-legend' }, 'MUI legend')
19
- : null,
20
- ));
21
-
22
- const i18n = i18next.createInstance();
23
- i18n.init({
24
- lng: 'en',
25
- resources: {
26
- en: {
27
- translation: {
28
- 'TimeSeriesChart.RANGE_LABEL': 'Range',
29
- 'TimeSeriesChart.RANGE_1_DAY': '1 day',
30
- 'TimeSeriesChart.RANGE_1_WEEK': '1 week',
31
- 'TimeSeriesChart.RANGE_1_MONTH': '1 month',
32
- 'TimeSeriesChart.RANGE_1_YEAR': '1 year',
33
- 'TimeSeriesChart.SERIES_LABEL': 'Series',
34
- 'ChartFrame.EMPTY_DEFAULT': 'No data available.',
35
- 'ChartFrame.LOADING': 'Loading chart.',
36
- 'ChartFrame.ERROR_DEFAULT': 'The chart could not be loaded.',
37
- },
38
- },
39
- },
40
- interpolation: { escapeValue: false },
41
- });
42
-
43
- const MULTI_SERIES = {
44
- xLabels: ['Mon', 'Tue'],
45
- series: [
46
- { key: 'users', label: 'Users', data: [1, 2] },
47
- { key: 'hours', label: 'Presence hours', data: [3, 4] },
48
- ],
49
- };
50
-
51
- function renderChart(data = MULTI_SERIES) {
52
- return render(React.createElement(
53
- ThemeProvider,
54
- { theme: createTheme() },
55
- React.createElement(
56
- I18nextProvider,
57
- { i18n },
58
- React.createElement(TimeSeriesChart, {
59
- title: 'Activity',
60
- xAxisLabel: 'Day',
61
- yAxisLabel: 'Count',
62
- data,
63
- }),
64
- ),
65
- ),
66
- );
67
- }
68
-
69
- describe('TimeSeriesChart toolbar legend', () => {
70
- afterEach(() => {
71
- cleanup();
72
- vi.clearAllMocks();
73
- });
74
-
75
- it('removes the MUI legend when the toolbar names and toggles multiple series', () => {
76
- renderChart();
77
-
78
- expect(chartSpy.mock.calls.at(-1)[0].hideLegend).toBe(true);
79
- expect(screen.queryByTestId('mui-legend')).toBeNull();
80
- });
81
-
82
- it('keeps an accessible name on every toolbar series toggle', () => {
83
- renderChart();
84
-
85
- expect(screen.getByRole('checkbox', { name: 'Users' })).toBeTruthy();
86
- expect(screen.getByRole('checkbox', { name: 'Presence hours' })).toBeTruthy();
87
- expect(screen.getAllByTestId('series-colour-dot')).toHaveLength(2);
88
- });
89
-
90
- it('still hides the redundant MUI legend for a single series', () => {
91
- renderChart({
92
- xLabels: ['Mon', 'Tue'],
93
- series: [{ key: 'users', label: 'Users', data: [1, 2] }],
94
- });
95
-
96
- expect(chartSpy.mock.calls.at(-1)[0].hideLegend).toBe(true);
97
- expect(screen.queryByTestId('mui-legend')).toBeNull();
98
- });
99
- });
@@ -1,218 +0,0 @@
1
- // @vitest-environment jsdom
2
- import React from 'react';
3
- import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
4
- import { cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
5
- import { I18nextProvider } from 'react-i18next';
6
- import i18next from 'i18next';
7
-
8
- const authApi = vi.hoisted(() => ({
9
- deleteUser: vi.fn(),
10
- fetchUsersList: vi.fn(),
11
- sendAdminInvite: vi.fn(),
12
- updateUserRole: vi.fn(),
13
- }));
14
-
15
- vi.mock('../src/auth/authApi', () => authApi);
16
-
17
- import { authTranslations } from '../src/i18n/authTranslations';
18
- import { BulkInviteCsvTab } from '../src/components/BulkInviteCsvTab';
19
- import { UserInviteComponent } from '../src/components/UserInviteComponent';
20
- import { UserListComponent } from '../src/components/UserListComponent';
21
-
22
- const germanResources = Object.fromEntries(
23
- Object.entries(authTranslations).map(([key, value]) => [key, value.de]),
24
- );
25
- const englishResources = Object.fromEntries(
26
- Object.entries(authTranslations).map(([key, value]) => [key, value.en]),
27
- );
28
- const i18n = i18next.createInstance();
29
- i18n.init({
30
- lng: 'de',
31
- fallbackLng: 'de',
32
- resources: { de: { translation: germanResources } },
33
- keySeparator: false,
34
- nsSeparator: false,
35
- interpolation: { escapeValue: false },
36
- });
37
- const englishI18n = i18next.createInstance();
38
- englishI18n.init({
39
- lng: 'en',
40
- fallbackLng: 'en',
41
- resources: { en: { translation: englishResources } },
42
- keySeparator: false,
43
- nsSeparator: false,
44
- interpolation: { escapeValue: false },
45
- });
46
-
47
- const ENGLISH_DEFAULTS = [
48
- 'All Users',
49
- 'Search',
50
- 'Search users...',
51
- 'Rows per page:',
52
- 'of 1',
53
- 'Successful Login',
54
- 'Are you sure you want to delete this user?',
55
- 'Invite a new user',
56
- 'Bulk Invite via CSV',
57
- 'Upload a CSV file containing email addresses. Header "email" is supported.',
58
- 'Upload CSV',
59
- 'Send Invites',
60
- 'Invitation sent.',
61
- ];
62
-
63
- function withGermanI18n(children) {
64
- return <I18nextProvider i18n={i18n}>{children}</I18nextProvider>;
65
- }
66
-
67
- function withEnglishI18n(children) {
68
- return <I18nextProvider i18n={englishI18n}>{children}</I18nextProvider>;
69
- }
70
-
71
- function expectNoEnglishDefaults() {
72
- const text = document.body.textContent;
73
- for (const english of ENGLISH_DEFAULTS) {
74
- expect(text).not.toContain(english);
75
- }
76
- }
77
-
78
- describe('German user and invite screen translations', () => {
79
- beforeEach(() => {
80
- vi.clearAllMocks();
81
- authApi.fetchUsersList.mockResolvedValue([
82
- {
83
- id: 1,
84
- email: 'person@example.com',
85
- first_name: 'Ada',
86
- role: 'student',
87
- is_new: true,
88
- successful_login: true,
89
- },
90
- ]);
91
- authApi.sendAdminInvite.mockResolvedValue({});
92
- });
93
-
94
- afterEach(() => {
95
- cleanup();
96
- });
97
-
98
- it('renders the empty-list and CSV-error strings in German too', async () => {
99
- authApi.fetchUsersList.mockResolvedValue([]);
100
- render(withGermanI18n(<UserListComponent currentUser={{ id: 99, is_superuser: true, role: 'admin' }} />));
101
- await waitFor(() => expect(screen.getByText('Keine Benutzer gefunden.')).toBeTruthy());
102
-
103
- cleanup();
104
-
105
- render(withGermanI18n(<BulkInviteCsvTab inviteFn={vi.fn()} />));
106
- const fileInput = document.querySelector('input[type="file"]');
107
- fireEvent.change(fileInput, {
108
- target: { files: [new File([''], 'empty.csv', { type: 'text/csv' })] },
109
- });
110
- await waitFor(() => expect(screen.getByText('Keine gültigen E-Mail-Adressen in der CSV-Datei gefunden.')).toBeTruthy());
111
- expectNoEnglishDefaults();
112
- });
113
-
114
- it('renders UserListComponent in German, including pagination and action feedback', async () => {
115
- const confirm = vi.spyOn(window, 'confirm').mockReturnValue(false);
116
- const alert = vi.spyOn(window, 'alert').mockImplementation(() => {});
117
-
118
- render(withGermanI18n(
119
- <UserListComponent
120
- currentUser={{ id: 99, is_superuser: true, role: 'admin' }}
121
- extraRowActions={[{
122
- key: 'failing-action',
123
- label: 'Aktion',
124
- onClick: () => Promise.reject({}),
125
- }]}
126
- />,
127
- ));
128
-
129
- await waitFor(() => expect(screen.getByText('Alle Benutzer')).toBeTruthy());
130
- expect(screen.getByLabelText('Suche')).toBeTruthy();
131
- expect(screen.getByPlaceholderText('Benutzer suchen...')).toBeTruthy();
132
- expect(screen.getByText('1–1 von 1')).toBeTruthy();
133
- for (const german of ['Neu', 'Erfolgreiche Anmeldung', 'Rolle', 'Aktionen', 'Zeilen pro Seite:', 'Löschen']) {
134
- expect(screen.getByText(german)).toBeTruthy();
135
- }
136
-
137
- fireEvent.click(screen.getByRole('button', { name: 'Löschen' }));
138
- expect(confirm).toHaveBeenCalledWith('Möchten Sie diesen Benutzer wirklich löschen?');
139
-
140
- fireEvent.click(screen.getByRole('button', { name: 'Aktion' }));
141
- await waitFor(() => expect(alert).toHaveBeenCalledWith('Vorgang fehlgeschlagen.'));
142
- expectNoEnglishDefaults();
143
- });
144
-
145
- it('renders the pagination range in English when the locale is English', async () => {
146
- render(withEnglishI18n(<UserListComponent currentUser={{ id: 99, is_superuser: true, role: 'admin' }} />));
147
-
148
- await waitFor(() => expect(screen.getByText('1–1 of 1')).toBeTruthy());
149
- });
150
-
151
- it('actually goes through the translation key, not a coincidental match with MUI\'s own default', async () => {
152
- // The real English wording is deliberately identical to MUI's own hardcoded default text
153
- // (both "{from}-{to} of {count}"), so the assertion above would still pass even if
154
- // labelDisplayedRows were reverted to unset entirely. Swap in a distinctive marker for just
155
- // this one key to prove the render genuinely resolves it through i18next, not MUI's fallback
156
- // (UCM-I18N-5 review, tests lens).
157
- const markerI18n = i18next.createInstance();
158
- markerI18n.init({
159
- lng: 'en',
160
- fallbackLng: 'en',
161
- resources: {
162
- en: {
163
- translation: { ...englishResources, 'UserList.DISPLAYED_ROWS': '__MARKER__ {{from}}-{{to}}/{{count}}' },
164
- },
165
- },
166
- keySeparator: false,
167
- nsSeparator: false,
168
- interpolation: { escapeValue: false },
169
- });
170
-
171
- render(
172
- <I18nextProvider i18n={markerI18n}>
173
- <UserListComponent currentUser={{ id: 99, is_superuser: true, role: 'admin' }} />
174
- </I18nextProvider>,
175
- );
176
-
177
- await waitFor(() => expect(screen.getByText('__MARKER__ 1-1/1')).toBeTruthy());
178
- });
179
-
180
- it('renders UserInviteComponent in German and translates the success message', async () => {
181
- render(withGermanI18n(<UserInviteComponent />));
182
-
183
- expect(screen.getByText('Neuen Benutzer einladen')).toBeTruthy();
184
- fireEvent.change(screen.getByLabelText('E-Mail-Adresse'), {
185
- target: { value: 'new@example.com' },
186
- });
187
- fireEvent.click(screen.getByRole('button', { name: 'Einladen' }));
188
-
189
- await waitFor(() => expect(screen.getByText('Einladung gesendet.')).toBeTruthy());
190
- expectNoEnglishDefaults();
191
- });
192
-
193
- it('renders BulkInviteCsvTab in German with translated progress and table copy', async () => {
194
- render(withGermanI18n(
195
- <BulkInviteCsvTab inviteFn={vi.fn().mockResolvedValue({})} />,
196
- ));
197
-
198
- expect(screen.getByText('Masseneinladung per CSV')).toBeTruthy();
199
- expect(screen.getByText('CSV-Datei mit E-Mail-Adressen hochladen. Header "email" wird unterstützt.')).toBeTruthy();
200
- expect(screen.getByRole('button', { name: 'CSV hochladen' })).toBeTruthy();
201
- expect(screen.getByRole('button', { name: 'Einladungen senden' })).toBeTruthy();
202
-
203
- const fileInput = document.querySelector('input[type="file"]');
204
- fireEvent.change(fileInput, {
205
- target: { files: [new File(['email\nperson@example.com'], 'users.csv', { type: 'text/csv' })] },
206
- });
207
- await waitFor(() => expect(screen.getByText('1 E-Mail-Adressen geladen')).toBeTruthy());
208
-
209
- fireEvent.click(screen.getByRole('button', { name: 'Einladungen senden' }));
210
- await waitFor(() => expect(screen.getByText('1 / 1 Einladungen gesendet.')).toBeTruthy());
211
- for (const german of ['Einladung gesendet.', 'Erfolgreich', 'Status', 'Details']) {
212
- expect(screen.getByText(german)).toBeTruthy();
213
- }
214
- expect(document.body.textContent).toContain('1 / 1 verarbeitet');
215
- expect(document.body.textContent).toContain('1 erfolgreich');
216
- expectNoEnglishDefaults();
217
- });
218
- });
@@ -1,18 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "rootDir": "./src",
4
- "outDir": "dist",
5
- "allowJs": true,
6
- "checkJs": false,
7
- "jsx": "react-jsx",
8
- "module": "ESNext",
9
- "target": "ES2017",
10
- "moduleResolution": "Node",
11
- "ignoreDeprecations": "6.0",
12
- "esModuleInterop": true,
13
- "skipLibCheck": true,
14
- "noEmit": false,
15
- "declaration": false
16
- },
17
- "include": ["src"]
18
- }
package/vite.config.mjs DELETED
@@ -1,6 +0,0 @@
1
- import { defineConfig } from 'vite';
2
- import react from '@vitejs/plugin-react';
3
-
4
- export default defineConfig({
5
- plugins: [react()],
6
- });
@@ -1,74 +0,0 @@
1
- # WORK ORDER AUTH-1 — Password forms: state the rules (proactive helperText + inline validator)
2
-
3
- Tier 2 (touches `ui-core-micha` = shared-core). ucm-only, **zero per-app work** (consumers get it
4
- on their next ucm pin-bump). Origin: Spesix field report 2026-08-06 — a first-time admin setting a
5
- password from an invitation link could not tell what the password had to satisfy; the only way to
6
- learn the rules was to submit and read the rejection.
7
-
8
- ## A. Envelope (authoritative WHAT / WHY)
9
-
10
- ### Goal
11
- Tell the user the password rules **before** they submit, and give **instant frontend feedback** on
12
- the two most common failures — so the invitation/first-contact screen no longer rejects people
13
- without ever saying what it wants.
14
-
15
- ### Scope — exactly the two forms that take a NEW password
16
- - `src/components/PasswordSetForm.jsx` (invitation set + reset-confirm).
17
- - `src/components/PasswordChangeForm.jsx`.
18
- - **NOT** `PasswordResetRequestForm.jsx` — verified it takes **email only** (`type="email"`,
19
- `onSubmit(email)`), no password field. The Spesix report listed it by mistake.
20
-
21
- ### Deliverable 1 — proactive helperText (the rules, stated)
22
- - Render `helperText` on the **new-password** `TextField` in both forms, default =
23
- `t('Auth.PASSWORD_RULES_HINT')`.
24
- - Add `Auth.PASSWORD_RULES_HINT` to `src/i18n/authTranslations.ts` in **de/fr/en**, stating the
25
- baseline the template ships with. The baseline is authoritative from dcm
26
- `settings_base.py:493-498` (the 4 Django defaults): **min 8 chars · not entirely numeric · not a
27
- common password · not too similar to personal info.** Suggested de: „Mindestens 8 Zeichen, nicht
28
- nur Zahlen, kein gängiges Passwort." (keep it concise; the similarity rule is niche — translator
29
- finalises).
30
- - Add an **optional prop** `passwordRulesHint` (string) to both forms — overrides the default so an
31
- app that configures custom validators can pass matching text. This is the "Better" variant: cheap
32
- effort, removes the only real objection (divergence from a customised backend).
33
-
34
- ### Deliverable 2 — inline validator (signal before the backend rejects)
35
- Before calling `onSubmit(...)`, validate the two rules that are cheap and faithful to replicate,
36
- reusing the existing local-error mechanism (`localErrorKey` — the forms already do this for
37
- empty/mismatch):
38
- - **min length 8** → `Auth.PASSWORD_TOO_SHORT_LOCAL`,
39
- - **not entirely numeric** → `Auth.PASSWORD_NUMERIC_LOCAL`.
40
- Add both keys (de/fr/en). **Deliberately NOT** replicating CommonPassword (needs the ~20k list in
41
- the browser) or UserAttributeSimilarity (needs user attributes the set-from-invite form doesn't
42
- have) — those stay backend-enforced; the helperText already warns about them, and AUTH-2 will
43
- translate their backend rejection. This is a **best-effort UX layer, not a security boundary** —
44
- the backend stays authoritative (frontend permissive, backend decides).
45
-
46
- ### Non-goals
47
- - Don't change the backend or the validators. Don't touch `PasswordResetRequestForm`. Don't touch
48
- the `onSubmit` contract or add API-error rendering (that's the deferred reactive error-prop, out
49
- of scope). No new screen → **no prototype** (trivial addition per `frontend-design`).
50
-
51
- ### Tier / rollout
52
- Tier 2 (shared-core). ucm has **no staging** → publish-from-main: land on `main` → **minor version
53
- bump** (2.26.4 → 2.27.0) → consumers adopt on their own pin-bump. **Spesix is pinned at 2.5.0**
54
- (far behind) — it won't receive this until it does a separate, larger ucm pin-bump; that's an
55
- app-side decision, not part of this WO.
56
-
57
- ### Required tests
58
- ucm component tests: helperText renders on both forms (and the `passwordRulesHint` prop overrides);
59
- the inline validator blocks submit + shows the right message for a <8-char and an all-numeric
60
- password; de/fr/en keys present for all 3 new strings.
61
-
62
- ## B. Implementation map (seed)
63
- - `src/components/PasswordSetForm.jsx` (new-password `TextField` ~L48) + `PasswordChangeForm.jsx` —
64
- add `helperText` + the pre-`onSubmit` length/numeric check via `localErrorKey`; add the
65
- `passwordRulesHint` prop.
66
- - `src/i18n/authTranslations.ts` — 3 new keys × de/fr/en: `PASSWORD_RULES_HINT`,
67
- `PASSWORD_TOO_SHORT_LOCAL`, `PASSWORD_NUMERIC_LOCAL`.
68
- - `package.json` — minor bump at finalize (Orchestrator, on green).
69
-
70
- **Review:** Tier 2 → independent `reviewer` + **`ui_reviewer`** (frontend diff, i18n coverage).
71
- **Directive:** implementer leaves the diff; Orchestrator reviews + bumps the version + commits on
72
- green. Codex out until 2026-08-06 → direct Claude.
73
-
74
- **Companion:** AUTH-2 (translate the backend auth error codes — the *reactive* half, broader).
@@ -1,74 +0,0 @@
1
- # WORK ORDER AUTH-2 — Translate backend auth error codes (stop leaking raw codes to users)
2
-
3
- Tier 2 (touches `ui-core-micha` = shared-core). ucm-only, **zero per-app work** for the core (the
4
- components already call `t(err.code)` — they just lack the translations). Found alongside the
5
- AUTH-1 password report: ucm surfaces raw backend error **codes**, not human text.
6
-
7
- ## A. Envelope (authoritative WHAT / WHY)
8
-
9
- ### Problem (verified)
10
- `src/auth/apiClient.jsx:107-124` extracts `err.code` (a machine code) from the backend/allauth
11
- response. Components then render it as an i18n key: `setErrorKey(err.code || 'Auth.X_FAILED')` →
12
- `t(errorKey)` (e.g. `SecurityComponent.jsx:60/71`, `ProfileComponent.jsx:143`,
13
- `MfaLoginComponent.jsx:53`), or `t(err?.code || 'Auth.X_FAILED', 'fallback')`. **The i18n
14
- catalogue has no entries for these codes** (grep for `email_password_mismatch` / `password_too_*`
15
- = empty), so i18next returns the key unchanged and the user sees the literal
16
- **`email_password_mismatch`** (or a generic fallback that hides the specific reason). This affects
17
- **all** rendering auth screens — login, change-password, MFA, profile — not just passwords.
18
-
19
- ### Goal
20
- Render translated, human text for the known backend auth error codes, so the specific reason
21
- (including the password rules AUTH-1's frontend validator can't replicate — common-password,
22
- similarity) shows wherever a ucm component already renders an auth error. Because the components
23
- already `t(err.code)`, this is achieved by **adding the translations** — no component change, no
24
- app change.
25
-
26
- ### Deliverable
27
- 1. **Enumerate the backend auth error codes** actually emitted — from allauth-headless + Django
28
- password-validator codes, confirmed against real responses (don't guess the full set). Known
29
- starters: `email_password_mismatch`, `password_too_short`, `password_too_common`,
30
- `password_entirely_numeric` (verify exact spelling), `password_too_similar`, and the current-
31
- password / incorrect-password codes surfaced by the change-password flow.
32
- 2. Add i18n entries for each, **de/fr/en**, in `src/i18n/authTranslations.ts`, **keyed by the raw
33
- code string** (so the existing `t(err.code)` resolves as a drop-in — no component edit).
34
- 3. Keep the generic `Auth.X_FAILED` fallback for unknown/unmapped codes (no regression).
35
-
36
- ### Design note — keying (decision to confirm in planning)
37
- Raw-code keys (`"password_too_short": {...}`) are the **drop-in** fix matching the existing
38
- `t(err.code)` calls — pure ucm, no backend change. Cleaner but two-repo alternative: have dcm's
39
- exception handler set a namespaced `i18nKey` per error (apiClient already reads `data.i18nKey`,
40
- `apiClient.jsx:107`) → ucm keys become `Auth.ERROR.*`. Prefer the drop-in unless the operator wants
41
- the namespaced contract.
42
-
43
- ### Scope boundary (honest)
44
- This fixes screens that **render** the error (login, change-password via `SecurityComponent`, MFA,
45
- profile). It does **NOT** reach the invitation **`PasswordSetForm`** — that form **delegates**
46
- `onSubmit` and renders no API error at all; its proactive coverage is AUTH-1 (helperText +
47
- validator), and its full reactive display would need the deferred per-app error-prop.
48
-
49
- ### Non-goals
50
- No component/contract change (translations only, unless the namespaced-`i18nKey` option is chosen →
51
- then a small dcm touch). No new error surfaces. Don't remove the generic fallbacks.
52
-
53
- ### Tier / rollout
54
- Tier 2 (shared-core). Publish-from-main → minor bump → consumers adopt on pin-bump. Zero per-app
55
- for the core.
56
-
57
- ### Required tests
58
- `t(<code>)` resolves to translated text for each mapped code (de/fr/en); an unmapped code still
59
- falls back to the generic `Auth.*_FAILED`; a representative render path (e.g. `SecurityComponent`
60
- change-password error) shows human text, not the raw code.
61
-
62
- ## B. Implementation map (seed)
63
- - `src/i18n/authTranslations.ts` — add the enumerated code→text entries (de/fr/en).
64
- - (verification only) `src/auth/apiClient.jsx:107-124` + the `setErrorKey(err.code…)` /
65
- `t(err.code…)` call sites — confirm they resolve against the new entries; no edit expected.
66
- - `package.json` — minor bump at finalize.
67
- - (optional, if namespaced-`i18nKey` chosen) `django-core-micha` auth exception handler — set
68
- `i18nKey` per error.
69
-
70
- **Review:** Tier 2 → `reviewer` + **`ui_reviewer`** (i18n/translation coverage — the whole point).
71
- **Directive:** implementer leaves the diff; Orchestrator reviews + bumps version + commits on
72
- green. Codex out until 2026-08-06 → direct Claude.
73
-
74
- **Companion:** AUTH-1 (the proactive helperText + inline validator — the other half).