@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,539 +0,0 @@
1
- import apiClient from './apiClient';
2
- import { HEADLESS_BASE, USERS_BASE, ACCESS_CODES_BASE } from './authConfig';
3
- import { normaliseApiError } from '../utils/auth-errors'; // Beachte den Pfad zu deiner errors.js
4
-
5
- // --- Internal Helper for CSRF ---
6
- function getCsrfToken() {
7
- if (typeof document === 'undefined' || !document.cookie) return null;
8
- const match = document.cookie.match(/(?:^|; )csrftoken=([^;]+)/);
9
- return match ? match[1] : null;
10
- }
11
-
12
- // -----------------------------
13
- // Session & User Core
14
- // -----------------------------
15
-
16
- export async function fetchCurrentUser() {
17
- // Bootstrap-Probe: 401 darf nicht in einen Login-Redirect umschlagen,
18
- // damit Public-Landings auf "/" sichtbar bleiben. `skipAuthRedirect` ist eine
19
- // client-seitige axios-Config-Property und wird nicht ans Backend gesendet.
20
- const res = await apiClient.get(`${USERS_BASE}/current/`, {
21
- skipAuthRedirect: true,
22
- });
23
- return res.data;
24
- }
25
-
26
- export async function fetchAuthMethods() {
27
- const res = await apiClient.get('/api/auth-methods/');
28
- return res.data || {};
29
- }
30
-
31
- export async function fetchAuthPolicy() {
32
- try {
33
- const res = await apiClient.get(`${USERS_BASE}/auth-policy/`);
34
- return res.data || {};
35
- } catch (error) {
36
- throw normaliseApiError(error, 'Auth.AUTH_POLICY_FETCH_FAILED');
37
- }
38
- }
39
-
40
- export async function updateAuthPolicy(payload) {
41
- try {
42
- const res = await apiClient.patch(`${USERS_BASE}/auth-policy/`, payload);
43
- return res.data || {};
44
- } catch (error) {
45
- throw normaliseApiError(error, 'Auth.AUTH_POLICY_UPDATE_FAILED');
46
- }
47
- }
48
-
49
- export async function updateUserProfile(data) {
50
- try {
51
- const res = await apiClient.patch(`${USERS_BASE}/current/`, data);
52
- return res.data;
53
- } catch (error) {
54
- throw normaliseApiError(error, 'Auth.PROFILE_UPDATE_FAILED');
55
- }
56
- }
57
-
58
- function normalizeStatementText(data) {
59
- if (typeof data === 'string') return data;
60
- if (data && typeof data.content === 'string') return data.content;
61
- return '';
62
- }
63
-
64
- export async function fetchPrivacyStatement() {
65
- const res = await apiClient.get('/api/utils/privacy/');
66
- return normalizeStatementText(res.data);
67
- }
68
-
69
- export async function fetchCookieStatement() {
70
- const res = await apiClient.get('/api/utils/cookie/');
71
- return normalizeStatementText(res.data);
72
- }
73
-
74
- export async function fetchHeadlessSession() {
75
- const res = await apiClient.get(`${HEADLESS_BASE}/auth/session`);
76
- return res.data;
77
- }
78
-
79
- export async function logoutSession() {
80
- try {
81
- const headers = {};
82
- const token = getCsrfToken();
83
- if (token) headers['X-CSRFToken'] = token;
84
-
85
- await apiClient.delete(`${HEADLESS_BASE}/auth/session`, { headers });
86
- } catch (error) {
87
- // 401/404 beim Logout ignorieren wir
88
- if (error.response && [401, 404, 410].includes(error.response.status)) return;
89
- console.error('Logout error:', error);
90
- }
91
- }
92
-
93
- // -----------------------------
94
- // Authentication: Password & MFA
95
- // -----------------------------
96
-
97
- export async function loginWithPassword(email, password) {
98
- try {
99
- await apiClient.post(`${HEADLESS_BASE}/auth/login`, { email, password });
100
- // Nach erfolgreichem Login User holen
101
- const user = await fetchCurrentUser();
102
- return { user, needsMfa: false };
103
- } catch (error) {
104
- const status = error.response?.status;
105
- const body = error.response?.data;
106
-
107
- // Prüfen auf Allauth Headless MFA Flow (401 + flows)
108
- const flows = body?.data?.flows || body?.flows || [];
109
- const mfaFlow = Array.isArray(flows) ? flows.find((f) => f.id === 'mfa_authenticate') : null;
110
-
111
- if (status === 401 && mfaFlow && mfaFlow.is_pending) {
112
- return { needsMfa: true, availableTypes: mfaFlow.types || [] };
113
- }
114
-
115
- // 409 = Already logged in
116
- if (status === 409) {
117
- try {
118
- const user = await fetchCurrentUser();
119
- return { user, needsMfa: false };
120
- } catch (retryError) {
121
- throw normaliseApiError(retryError, 'Auth.LOGIN_FAILED');
122
- }
123
- }
124
-
125
- throw normaliseApiError(error, 'Auth.LOGIN_FAILED');
126
- }
127
- }
128
-
129
- export async function authenticateWithMFA({ code, credential }) {
130
- const payload = {};
131
- if (code) payload.code = code;
132
- if (credential) payload.credential = credential;
133
-
134
- try {
135
- const res = await apiClient.post(`${HEADLESS_BASE}/auth/2fa/authenticate`, payload);
136
- return res.data;
137
- } catch (error) {
138
- throw normaliseApiError(error, 'Auth.MFA_AUTHENTICATE_FAILED');
139
- }
140
- }
141
-
142
- // -----------------------------
143
- // Password Management
144
- // -----------------------------
145
-
146
- export async function requestPasswordReset(email) {
147
- try {
148
- await apiClient.post(`${USERS_BASE}/reset-request/`, { email });
149
- } catch (error) {
150
- throw normaliseApiError(error, 'Auth.RESET_REQUEST_FAILED');
151
- }
152
- }
153
-
154
- export async function resetPasswordWithKey(key, newPassword) {
155
- try {
156
- await apiClient.post(`${HEADLESS_BASE}/auth/password/reset/key`, { key, password: newPassword });
157
- } catch (error) {
158
- throw normaliseApiError(error, 'Auth.RESET_WITH_KEY_FAILED');
159
- }
160
- }
161
-
162
- export async function changePassword(currentPassword, newPassword) {
163
- try {
164
- await apiClient.post(`${HEADLESS_BASE}/account/password/change`, {
165
- current_password: currentPassword,
166
- new_password: newPassword,
167
- });
168
- } catch (error) {
169
- throw normaliseApiError(error, 'Auth.PASSWORD_CHANGE_FAILED');
170
- }
171
- }
172
-
173
- // Custom UID/Token Reset Flow
174
- export async function verifyResetToken(uid, token) {
175
- try {
176
- const res = await apiClient.get(`${USERS_BASE}/password-reset/${uid}/${token}/`);
177
- return res.data;
178
- } catch (error) {
179
- throw normaliseApiError(error, 'Auth.RESET_LINK_INVALID');
180
- }
181
- }
182
-
183
- export async function setNewPassword(uid, token, newPassword) {
184
- try {
185
- const res = await apiClient.post(`${USERS_BASE}/password-reset/${uid}/${token}/`, { new_password: newPassword });
186
- return res.data;
187
- } catch (error) {
188
- throw normaliseApiError(error, 'Auth.RESET_PASSWORD_FAILED');
189
- }
190
- }
191
-
192
- // -----------------------------
193
- // WebAuthn / Passkeys (API Calls Only)
194
- // -----------------------------
195
-
196
- export async function getPasskeyRegistrationOptions() {
197
- const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/webauthn`, {
198
- params: { passwordless: true }
199
- });
200
- // Extrahiere nested data Struktur von Allauth
201
- const data = res.data?.data || res.data;
202
- return data.creation_options || data;
203
- }
204
-
205
- export async function completePasskeyRegistration(credentialJson, name) {
206
- const res = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/webauthn`, {
207
- credential: credentialJson,
208
- name
209
- });
210
- return res.data;
211
- }
212
-
213
- export async function getPasskeyLoginOptions() {
214
- const res = await apiClient.get(`${HEADLESS_BASE}/auth/webauthn/login`);
215
- const data = res.data?.data || res.data;
216
- return data.request_options || data;
217
- }
218
-
219
- export async function completePasskeyLogin(credentialJson) {
220
- const res = await apiClient.post(`${HEADLESS_BASE}/auth/webauthn/login`, {
221
- credential: credentialJson
222
- });
223
- return res.data;
224
- }
225
-
226
- export async function fetchPasskeys() {
227
- try {
228
- const res = await apiClient.get(`${USERS_BASE}/passkeys/`);
229
- return Array.isArray(res.data) ? res.data : [];
230
- } catch (error) {
231
- throw normaliseApiError(error, 'Auth.PASSKEY_LIST_FAILED');
232
- }
233
- }
234
-
235
- export async function deletePasskey(id) {
236
- try {
237
- await apiClient.delete(`${USERS_BASE}/passkeys/${id}/`);
238
- } catch (error) {
239
- throw normaliseApiError(error, 'Auth.PASSKEY_DELETE_FAILED');
240
- }
241
- }
242
-
243
- // -----------------------------
244
- // Authenticators (TOTP & Recovery)
245
- // -----------------------------
246
-
247
- export async function fetchAuthenticators() {
248
- const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators`);
249
- const body = res.data || {};
250
- return Array.isArray(body.data) ? body.data : (Array.isArray(body) ? body : []);
251
- }
252
-
253
- export async function requestTotpKey() {
254
- try {
255
- const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/totp`);
256
- const data = res.data?.data || res.data;
257
- return { exists: true, authenticator: data };
258
- } catch (error) {
259
- // 404 bedeutet: Noch kein TOTP eingerichtet -> Wir bekommen das Secret zum Einrichten
260
- if (error.response?.status === 404) {
261
- const meta = error.response.data?.meta || {};
262
- return {
263
- exists: false,
264
- secret: meta.secret,
265
- key_uri: meta.totp_url || meta.totp_uri || meta.key_uri,
266
- };
267
- }
268
- throw normaliseApiError(error, 'Auth.TOTP_REQUEST_FAILED');
269
- }
270
- }
271
-
272
- export async function activateTotp(code) {
273
- try {
274
- await apiClient.post(`${HEADLESS_BASE}/account/authenticators/totp`, { code });
275
- } catch (error) {
276
- throw normaliseApiError(error, 'Auth.TOTP_ACTIVATE_FAILED');
277
- }
278
- }
279
-
280
- export async function deactivateTotp() {
281
- try {
282
- await apiClient.delete(`${HEADLESS_BASE}/account/authenticators/totp`);
283
- } catch (error) {
284
- throw normaliseApiError(error, 'Auth.TOTP_DEACTIVATE_FAILED');
285
- }
286
- }
287
-
288
- export async function fetchRecoveryCodes() {
289
- try {
290
- // Versuch, Codes zu laden
291
- const res = await apiClient.get(`${HEADLESS_BASE}/account/authenticators/recovery-codes`);
292
- return res.data?.data || res.data;
293
- } catch (error) {
294
- // 404 -> Noch keine Codes -> Generieren
295
- if (error.response?.status === 404) {
296
- const resPost = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {});
297
- return resPost.data?.data || resPost.data;
298
- }
299
- throw normaliseApiError(error, 'Auth.RECOVERY_CODES_FETCH_FAILED');
300
- }
301
- }
302
-
303
- export async function generateRecoveryCodes() {
304
- try {
305
- const res = await apiClient.post(`${HEADLESS_BASE}/account/authenticators/recovery-codes`, {});
306
- return res.data?.data || res.data;
307
- } catch (error) {
308
- throw normaliseApiError(error, 'Auth.RECOVERY_CODES_GENERATE_FAILED');
309
- }
310
- }
311
-
312
- // -----------------------------
313
- // Invitations & Access Codes
314
- // -----------------------------
315
-
316
- export async function fetchAccessCodes() {
317
- try {
318
- const res = await apiClient.get(`${ACCESS_CODES_BASE}/`);
319
- return res.data || [];
320
- } catch (error) {
321
- throw normaliseApiError(error, 'Auth.ACCESS_CODE_LIST_FAILED');
322
- }
323
- }
324
-
325
- export async function createAccessCode(code) {
326
- try {
327
- const res = await apiClient.post(`${ACCESS_CODES_BASE}/`, { code });
328
- return res.data;
329
- } catch (error) {
330
- throw normaliseApiError(error, 'Auth.ACCESS_CODE_SAVE_FAILED');
331
- }
332
- }
333
-
334
- export async function deleteAccessCode(id) {
335
- try {
336
- await apiClient.delete(`${ACCESS_CODES_BASE}/${id}/`);
337
- } catch (error) {
338
- throw normaliseApiError(error, 'Auth.ACCESS_CODE_DELETE_FAILED');
339
- }
340
- }
341
-
342
- export async function validateAccessCode(code) {
343
- try {
344
- const res = await apiClient.post(`${ACCESS_CODES_BASE}/validate/`, { code });
345
- return res.data;
346
- } catch (error) {
347
- throw normaliseApiError(error, 'Auth.ACCESS_CODE_INVALID_OR_INACTIVE');
348
- }
349
- }
350
-
351
- export async function sendAdminInvite(email) {
352
- try {
353
- const res = await apiClient.post(`${USERS_BASE}/invite/`, { email });
354
- return res.data;
355
- } catch (error) {
356
- throw normaliseApiError(error, 'Auth.INVITE_FAILED');
357
- }
358
- }
359
-
360
- export async function submitRegistrationRequest({
361
- email,
362
- mode,
363
- accessCode,
364
- registrationContextToken,
365
- registrationContext,
366
- turnstileToken,
367
- }) {
368
- const payload = { email, mode };
369
- if (accessCode) payload.access_code = accessCode;
370
- if (registrationContextToken) {
371
- payload.registration_context_token = registrationContextToken;
372
- }
373
- if (registrationContext) {
374
- payload.registration_context = registrationContext;
375
- }
376
- if (turnstileToken) payload.turnstile_token = turnstileToken;
377
-
378
- try {
379
- const res = await apiClient.post(`${USERS_BASE}/register-request/`, payload);
380
- return res.data;
381
- } catch (error) {
382
- throw normaliseApiError(error, 'Auth.INVITE_FAILED');
383
- }
384
- }
385
-
386
- /**
387
- * S13: confirm a pending registration. The token comes from the email link;
388
- * the password is the new account's first password.
389
- */
390
- export async function confirmRegistration({ token, password }) {
391
- try {
392
- const res = await apiClient.post(`${USERS_BASE}/register-confirm/`, {
393
- token,
394
- password,
395
- });
396
- return res.data;
397
- } catch (error) {
398
- throw normaliseApiError(error, 'Auth.PENDING_TOKEN_INVALID');
399
- }
400
- }
401
-
402
- export async function createSignupQr(payload = {}) {
403
- try {
404
- const res = await apiClient.post(`${USERS_BASE}/signup-qr/`, payload);
405
- return res.data || {};
406
- } catch (error) {
407
- throw normaliseApiError(error, 'Auth.SIGNUP_QR_CREATE_FAILED');
408
- }
409
- }
410
-
411
- // -----------------------------
412
- // Recovery Support (Admin/Support Side)
413
- // -----------------------------
414
-
415
- export async function requestMfaSupportHelp(emailOrIdentifier, message = '') {
416
- const res = await apiClient.post(`${USERS_BASE}/mfa/support-help/`, {
417
- email: emailOrIdentifier,
418
- message
419
- });
420
- return res.data;
421
- }
422
-
423
- export async function fetchRecoveryRequests(status = 'pending') {
424
- const res = await apiClient.get('/api/support/recovery-requests/', { params: { status } });
425
- return res.data;
426
- }
427
-
428
- export async function approveRecoveryRequest(id, supportNote) {
429
- const res = await apiClient.post(`/api/support/recovery-requests/${id}/approve/`, {
430
- support_note: supportNote || ''
431
- });
432
- return res.data;
433
- }
434
-
435
- export async function rejectRecoveryRequest(id, supportNote) {
436
- const res = await apiClient.post(`/api/support/recovery-requests/${id}/reject/`, {
437
- support_note: supportNote || ''
438
- });
439
- return res.data;
440
- }
441
-
442
- // S164: server-side session handoff. After the email-link redirect lands the
443
- // SPA on `/login#recovery=ok`, the LoginPage fetches the plaintext recovery
444
- // token from the user's server session (set by `recovery_complete_view`).
445
- // The endpoint pops the token on every read — a single shot per browser
446
- // navigation — so a navigated-away tab cannot reuse the entry.
447
- export async function fetchRecoverySessionToken() {
448
- try {
449
- const res = await apiClient.get('/api/auth/recovery/session-token/', {
450
- // Visiting `/login` without a pending recovery session is the common
451
- // case; the 404 it returns must not bubble up as a global "session
452
- // expired" auth error in the app shell.
453
- skipAuthRedirect: true,
454
- });
455
- return res?.data?.token || null;
456
- } catch (err) {
457
- if (err?.response?.status === 404) {
458
- // No pending recovery in this session — treat as a non-error so the
459
- // LoginPage can decide whether to surface a "link expired" message
460
- // based on the `#recovery=` hash sentinel it already inspects.
461
- return null;
462
- }
463
- throw normaliseApiError(err, 'Auth.RECOVERY_TOKEN_INVALID');
464
- }
465
- }
466
-
467
- export async function loginWithRecoveryPassword(email, password, token) {
468
- try {
469
- // S50 (django-core-micha >=2.13.1): token wird im POST-Body übergeben,
470
- // nicht mehr als URL-Path-Segment. Vermeidet Token-Leak in Referer-Headern,
471
- // Server-Access-Logs und Browser-History (POST-Credentials-Exchange).
472
- await apiClient.post('/api/support/recovery-requests/recovery-login/', {
473
- token,
474
- email,
475
- password
476
- });
477
- } catch (error) {
478
- throw normaliseApiError(error, 'Auth.RECOVERY_LOGIN_FAILED');
479
- }
480
- const user = await fetchCurrentUser();
481
- return { user, needsMfa: false };
482
- }
483
- /**
484
- * Ruft eine Liste von Benutzern ab (oft mit Pagination/Search).
485
- * Backend: GET /api/users/
486
- */
487
- export async function fetchUsersList(params = {}) {
488
- try {
489
- // params kann { page: 1, search: "...", ordering: "email" } enthalten
490
- const res = await apiClient.get(`${USERS_BASE}/`, { params });
491
- return res.data;
492
- } catch (error) {
493
- throw normaliseApiError(error, 'Auth.USER_LIST_FAILED');
494
- }
495
- }
496
-
497
- /**
498
- * Löscht einen Benutzer.
499
- * Backend: DELETE /api/users/{id}/
500
- */
501
- export async function deleteUser(userId) {
502
- try {
503
- await apiClient.delete(`${USERS_BASE}/${userId}/`);
504
- } catch (error) {
505
- throw normaliseApiError(error, 'Auth.USER_DELETE_FAILED');
506
- }
507
- }
508
-
509
- /**
510
- * Aktualisiert die Rolle eines Benutzers über die Custom Action.
511
- * Backend: PATCH /api/users/{id}/update-role/
512
- */
513
- export async function updateUserRole(userId, newRole) {
514
- try {
515
- const res = await apiClient.patch(`${USERS_BASE}/${userId}/update-role/`, {
516
- role: newRole,
517
- });
518
- return res.data;
519
- } catch (error) {
520
- throw normaliseApiError(error, 'Auth.USER_ROLE_UPDATE_FAILED');
521
- }
522
- }
523
-
524
- /**
525
- * Aktualisiert den Support-Status (z.B. is_support_agent Flag).
526
- * Backend: PATCH /api/users/{id}/ (Standard DRF Update mit Nested Profile)
527
- */
528
- export async function updateUserSupportStatus(userId, isSupportAgent) {
529
- try {
530
- // Backend expects flat field names, DRF maps via `source="profile.is_support_agent"`
531
- const payload = {
532
- is_support_agent: isSupportAgent,
533
- };
534
- const res = await apiClient.patch(`${USERS_BASE}/${userId}/`, payload);
535
- return res.data;
536
- } catch (error) {
537
- throw normaliseApiError(error, 'Auth.USER_SUPPORT_UPDATE_FAILED');
538
- }
539
- }
@@ -1,34 +0,0 @@
1
- // src/auth/authConfig.js
2
-
3
- // Basis-Pfad für die Headless-Allauth-API
4
- export const AUTH_BASE = '/api/auth';
5
-
6
- // Variante (z. B. "browser" oder später "app")
7
- export const HEADLESS_VARIANT = 'browser';
8
-
9
- // Version der Headless-API
10
- export const HEADLESS_VERSION = 'v1';
11
-
12
- // Vollständige Basis-URL für Auth-Calls zu allauth.headless
13
- export const HEADLESS_BASE = `${AUTH_BASE}/${HEADLESS_VARIANT}/${HEADLESS_VERSION}`;
14
-
15
- // Eigene User-API
16
- export const USERS_BASE = '/api/users';
17
-
18
- // NEU: Access-Code-API (kommt aus der Lib)
19
- export const ACCESS_CODES_BASE = '/api/access-codes';
20
-
21
- // CSRF-Endpoint (Django-View csrf_token_view)
22
- export const CSRF_URL = '/api/csrf/';
23
-
24
- // Konfiguration der Social-Provider
25
- export const SOCIAL_PROVIDERS = {
26
- google: 'google',
27
- microsoft: 'microsoft',
28
- };
29
-
30
- // Feature-Flags (falls du später Dinge toggeln willst)
31
- export const FEATURES = {
32
- passkeysEnabled: true, // kannst du später auf true setzen
33
- mfaEnabled: true,
34
- };
@@ -1,47 +0,0 @@
1
- // Promise broker for the reauthentication gate.
2
- //
3
- // When the response interceptor encounters a 401+reauthenticate, it calls
4
- // requestReauth() and awaits the returned promise. The ReauthModal resolves
5
- // or rejects that promise after the user submits (or cancels) the password
6
- // dialog. Concurrent 401s share the same pending promise so only one modal
7
- // ever appears.
8
-
9
- let _pendingResolve = null;
10
- let _pendingReject = null;
11
- let _reauthPromise = null;
12
- let _listeners = [];
13
-
14
- export function requestReauth() {
15
- if (_reauthPromise) return _reauthPromise;
16
- _reauthPromise = new Promise((resolve, reject) => {
17
- _pendingResolve = resolve;
18
- _pendingReject = reject;
19
- _listeners.forEach(fn => fn(true));
20
- });
21
- return _reauthPromise;
22
- }
23
-
24
- export function resolveReauth() {
25
- const resolve = _pendingResolve;
26
- _pendingResolve = null;
27
- _pendingReject = null;
28
- _reauthPromise = null;
29
- _listeners.forEach(fn => fn(false));
30
- if (resolve) resolve();
31
- }
32
-
33
- export function rejectReauth(error) {
34
- const reject = _pendingReject;
35
- _pendingResolve = null;
36
- _pendingReject = null;
37
- _reauthPromise = null;
38
- _listeners.forEach(fn => fn(false));
39
- if (reject) reject(error || new Error('Reauthentication cancelled'));
40
- }
41
-
42
- export function subscribe(fn) {
43
- _listeners = [..._listeners, fn];
44
- return () => {
45
- _listeners = _listeners.filter(l => l !== fn);
46
- };
47
- }
@@ -1,36 +0,0 @@
1
- import React from 'react';
2
- import { Button, Stack, TextField } from '@mui/material';
3
- import { useTranslation } from 'react-i18next';
4
-
5
- /**
6
- * Message input. Send is disabled while a turn runs, for an archived chat and while the connection is down;
7
- * Stop replaces it during a turn. Enter sends, Shift+Enter inserts a line break.
8
- */
9
- export function ChatComposer({ value = '', onChange, onSend, onStop, running = false, archived = false, connected = true, sx }) {
10
- const { t } = useTranslation();
11
- const blocked = archived || !connected;
12
- const canSend = !running && !blocked && value.trim().length > 0;
13
- const submit = () => { if (canSend) onSend?.(); };
14
- return (
15
- <Stack direction="row" alignItems="flex-end" gap={1} sx={{ p: { xs: 1, md: 2 }, borderTop: 1, borderColor: 'divider', ...sx }}>
16
- <TextField
17
- multiline
18
- maxRows={6}
19
- fullWidth
20
- size="small"
21
- value={value}
22
- disabled={blocked}
23
- placeholder={t('Chat.message')}
24
- slotProps={{ htmlInput: { 'aria-label': t('Chat.message') } }}
25
- onChange={(event) => onChange?.(event.target.value)}
26
- onKeyDown={(event) => {
27
- if (event.key === 'Enter' && !event.shiftKey && !event.nativeEvent?.isComposing) { event.preventDefault(); submit(); }
28
- }}
29
- />
30
- {running ? <Button variant="outlined" onClick={onStop}>{t('Chat.stop')}</Button> : null}
31
- <Button variant="contained" onClick={submit} disabled={!canSend}>{t('Chat.send')}</Button>
32
- </Stack>
33
- );
34
- }
35
-
36
- export default ChatComposer;