@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.
- package/CHANGELOG.md +31 -0
- package/README.md +7 -0
- package/dist/auth/UserMenu.js +1 -1
- package/dist/auth/apiClient.js +7 -6
- package/dist/chat/ChatList.js +1 -1
- package/dist/chat/ChatThread.js +2 -1
- package/dist/chat/ChatWorkspace.js +1 -1
- package/dist/chat/ModelPicker.js +2 -5
- package/dist/chat/kitSxRegistry.js +9 -0
- package/dist/chat/useChatSocket.js +1 -1
- package/dist/components/LoginForm.js +1 -1
- package/dist/components/SecurityComponent.js +1 -1
- package/dist/components/UserListComponent.js +2 -8
- package/dist/components/charts/ChartFrame.js +1 -1
- package/dist/components/charts/ScatterChart.js +2 -1
- package/dist/components/charts/kitSxRegistry.js +6 -0
- package/dist/entries/charts.js +6 -0
- package/dist/entries/chat.js +8 -0
- package/dist/entries/markdown.js +1 -0
- package/dist/index.js +0 -14
- package/dist/layout/SectionNav.js +1 -1
- package/dist/messaging/AttachmentList.js +2 -2
- package/dist/messaging/Composer.js +2 -1
- package/dist/messaging/ConversationLaunchers.js +1 -4
- package/dist/messaging/ConversationList.js +1 -1
- package/dist/messaging/DirectMessageLauncher.js +1 -1
- package/dist/messaging/MessagingProvider.js +0 -0
- package/dist/messaging/PollCard.js +7 -5
- package/dist/messaging/ReadTicks.js +2 -2
- package/dist/messaging/Thread.js +5 -3
- package/dist/notifications/NotificationBell.js +4 -7
- package/dist/notifications/NotificationSettings.js +1 -1
- package/dist/onboarding/OnboardingProvider.js +3 -6
- package/dist/pages/AccountPage.js +1 -2
- package/dist/pages/LoginPage.js +2 -3
- package/dist/pages/PasswordChangePage.js +2 -3
- package/dist/pages/PasswordInvitePage.js +2 -3
- package/dist/pages/PasswordResetRequestPage.js +2 -3
- package/dist/pages/SignUpPage.js +2 -3
- package/dist/pages/SignupConfirmPage.js +2 -3
- package/dist/theme/createAppTheme.js +5 -4
- package/dist/theme/kitSxEntry.js +11 -0
- package/dist/theme/kitSxRegistry.js +2 -15
- package/dist/theme/themeCompleteness.js +3 -12
- package/dist/utils/auth-errors.js +4 -3
- package/package.json +41 -16
- package/.github/workflows/publish.yml +0 -126
- package/DESIGN.md +0 -60
- package/WORK_ORDERS.md +0 -148
- package/dev/entries.jsx +0 -721
- package/dev/fixtures.js +0 -26
- package/dev/main.jsx +0 -75
- package/dev/mockTransport.jsx +0 -128
- package/docs/CHART-LAYOUT.md +0 -157
- package/docs/DARK-TOKENS.md +0 -140
- package/docs/TYPE-SCALE.md +0 -111
- package/docs/messaging-deviations.md +0 -118
- package/index.html +0 -12
- package/renovate.json +0 -10
- package/scripts/chart-api-census.mjs +0 -415
- package/src/auth/AuthContext.jsx +0 -158
- package/src/auth/ReauthModal.jsx +0 -82
- package/src/auth/UserMenu.jsx +0 -121
- package/src/auth/apiClient.jsx +0 -232
- package/src/auth/authApi.jsx +0 -539
- package/src/auth/authConfig.jsx +0 -34
- package/src/auth/reauth.js +0 -47
- package/src/chat/ChatComposer.jsx +0 -36
- package/src/chat/ChatList.jsx +0 -87
- package/src/chat/ChatThread.jsx +0 -128
- package/src/chat/ChatWorkspace.jsx +0 -244
- package/src/chat/MarkdownReply.jsx +0 -22
- package/src/chat/ModelPicker.jsx +0 -85
- package/src/chat/api.js +0 -18
- package/src/chat/useChatSocket.js +0 -32
- package/src/chat/wire.js +0 -7
- package/src/components/AccessCodeManager.jsx +0 -288
- package/src/components/AccessCodeSingleUseToggle.jsx +0 -92
- package/src/components/AllowedEmailDomainsManager.jsx +0 -92
- package/src/components/AuthFactorRequirementCard.jsx +0 -95
- package/src/components/BulkInviteCsvTab.jsx +0 -198
- package/src/components/EmptyState.jsx +0 -38
- package/src/components/LoginForm.jsx +0 -159
- package/src/components/MFAComponent.jsx +0 -350
- package/src/components/MfaLoginComponent.jsx +0 -252
- package/src/components/MobileBottomNav.jsx +0 -82
- package/src/components/PasskeysComponent.jsx +0 -252
- package/src/components/PasswordChangeForm.jsx +0 -87
- package/src/components/PasswordResetRequestForm.jsx +0 -43
- package/src/components/PasswordSetForm.jsx +0 -97
- package/src/components/ProfileComponent.jsx +0 -348
- package/src/components/QrSignupManager.jsx +0 -404
- package/src/components/QrSignupValidityManager.jsx +0 -106
- package/src/components/RegistrationMethodsManager.jsx +0 -150
- package/src/components/SecurityComponent.jsx +0 -141
- package/src/components/SocialLoginButtons.jsx +0 -83
- package/src/components/SoftChip.jsx +0 -93
- package/src/components/StatTile.jsx +0 -39
- package/src/components/SupportRecoveryRequestsTab.jsx +0 -482
- package/src/components/TurnstileWidget.jsx +0 -99
- package/src/components/UserInviteComponent.jsx +0 -76
- package/src/components/UserListComponent.jsx +0 -618
- package/src/components/charts/BarChart.jsx +0 -102
- package/src/components/charts/ChartFrame.jsx +0 -214
- package/src/components/charts/LineChart.jsx +0 -126
- package/src/components/charts/ScatterChart.jsx +0 -299
- package/src/components/charts/TimeSeriesChart.jsx +0 -300
- package/src/components/charts/chartDefaults.js +0 -644
- package/src/components/charts/chartLabels.js +0 -36
- package/src/components/charts/exportChart.js +0 -258
- package/src/components/charts/formatters.js +0 -39
- package/src/components/charts/palette.js +0 -33
- package/src/components/charts/yearTickInterval.js +0 -7
- package/src/i18n/authTranslations.ts +0 -2651
- package/src/i18n/chartsTranslations.ts +0 -91
- package/src/i18n/chatTranslations.ts +0 -55
- package/src/i18n/messagingTranslations.ts +0 -120
- package/src/i18n/notificationsTranslations.ts +0 -32
- package/src/i18n/onboardingTranslations.ts +0 -29
- package/src/i18n/sectionNavTranslations.ts +0 -20
- package/src/i18n/uiCoreTranslations.js +0 -29
- package/src/i18n/userMenuTranslations.ts +0 -5
- package/src/index.js +0 -158
- package/src/layout/PageLayout.jsx +0 -36
- package/src/layout/SectionNav.jsx +0 -320
- package/src/messaging/AttachmentList.jsx +0 -145
- package/src/messaging/Composer.jsx +0 -197
- package/src/messaging/ConversationLaunchers.jsx +0 -51
- package/src/messaging/ConversationList.jsx +0 -109
- package/src/messaging/DirectMessageLauncher.jsx +0 -112
- package/src/messaging/MessageBubble.jsx +0 -183
- package/src/messaging/MessagingProvider.jsx +0 -0
- package/src/messaging/MessagingScopeConfig.jsx +0 -24
- package/src/messaging/PollCard.jsx +0 -163
- package/src/messaging/ReactionBar.jsx +0 -43
- package/src/messaging/ReadTicks.jsx +0 -82
- package/src/messaging/Thread.jsx +0 -195
- package/src/messaging/api.js +0 -48
- package/src/messaging/composerImageCompression.js +0 -35
- package/src/messaging/linkifyText.jsx +0 -37
- package/src/notifications/NotificationBell.jsx +0 -84
- package/src/notifications/NotificationSettings.jsx +0 -330
- package/src/notifications/NotificationsProvider.jsx +0 -224
- package/src/notifications/PopupSurface.jsx +0 -105
- package/src/notifications/api.js +0 -55
- package/src/notifications/feedApi.js +0 -18
- package/src/notifications/realtime.jsx +0 -138
- package/src/notifications/serviceWorker/sw.js +0 -50
- package/src/onboarding/OnboardingProvider.jsx +0 -326
- package/src/onboarding/OnboardingWizard.jsx +0 -61
- package/src/onboarding/WizardDialogShell.jsx +0 -51
- package/src/onboarding/api.js +0 -13
- package/src/onboarding/stepSelection.js +0 -16
- package/src/onboarding/steps/BrowserPushStep.jsx +0 -121
- package/src/onboarding/steps/CompleteNameStep.jsx +0 -46
- package/src/onboarding/steps/CookieConsentStep.jsx +0 -133
- package/src/onboarding/steps/PwaInstallStep.jsx +0 -47
- package/src/pages/AccountPage.jsx +0 -394
- package/src/pages/LoginPage.jsx +0 -343
- package/src/pages/PasswordChangePage.jsx +0 -62
- package/src/pages/PasswordInvitePage.jsx +0 -177
- package/src/pages/PasswordResetRequestPage.jsx +0 -68
- package/src/pages/SignUpPage.jsx +0 -268
- package/src/pages/SignupConfirmPage.jsx +0 -155
- package/src/testing/checkKitIntegration.js +0 -233
- package/src/theme/createAppTheme.js +0 -423
- package/src/theme/fonts.js +0 -3
- package/src/theme/index.js +0 -21
- package/src/theme/kitSxRegistry.js +0 -285
- package/src/theme/themeCompleteness.js +0 -1045
- package/src/theme/tokens.js +0 -478
- package/src/utils/auth-errors.js +0 -76
- package/src/utils/authService.js +0 -223
- package/src/utils/resolveErrorText.js +0 -28
- package/src/utils/webauthn.js +0 -51
- package/tests/AccountPage.profileStatements.test.jsx +0 -162
- package/tests/AccountPage.test.jsx +0 -200
- package/tests/AuthContext.test.jsx +0 -129
- package/tests/BarChart.test.jsx +0 -112
- package/tests/BrowserPushStep.test.jsx +0 -110
- package/tests/ChartFrame.test.jsx +0 -336
- package/tests/ConversationList.test.jsx +0 -144
- package/tests/CookieConsentStep.test.jsx +0 -69
- package/tests/EmptyState.test.jsx +0 -62
- package/tests/LineChart.test.jsx +0 -80
- package/tests/MessagingProvider.test.jsx +0 -50
- package/tests/MobileBottomNav.test.jsx +0 -319
- package/tests/NotificationBell.test.jsx +0 -60
- package/tests/NotificationSettings.test.jsx +0 -276
- package/tests/NotificationsProvider.test.jsx +0 -240
- package/tests/OnboardingProvider.test.jsx +0 -294
- package/tests/OnboardingWizard.test.jsx +0 -143
- package/tests/PasswordChangeForm.test.jsx +0 -70
- package/tests/PasswordInvitePage.test.jsx +0 -142
- package/tests/PasswordSetForm.test.jsx +0 -70
- package/tests/PopupSurface.test.jsx +0 -142
- package/tests/ProfileComponent.refresh.test.jsx +0 -194
- package/tests/QrSignupManager.registrationContext.test.jsx +0 -106
- package/tests/QrSignupManagerInfoBox.test.jsx +0 -49
- package/tests/ScatterChart.test.jsx +0 -270
- package/tests/SectionNav.test.jsx +0 -363
- package/tests/SignUpPage.test.jsx +0 -208
- package/tests/SoftChip.test.jsx +0 -105
- package/tests/StatTile.test.jsx +0 -57
- package/tests/Thread.test.jsx +0 -151
- package/tests/TimeSeriesChart.test.jsx +0 -367
- package/tests/UserListComponent.test.jsx +0 -192
- package/tests/UserMenu.test.jsx +0 -171
- package/tests/apiClientLanguage.test.js +0 -33
- package/tests/apiClientPublicPaths.test.js +0 -178
- package/tests/authApiLogin.test.js +0 -42
- package/tests/authApiRegistration.test.js +0 -31
- package/tests/authErrorCodeRendering.test.jsx +0 -77
- package/tests/authErrors.test.js +0 -74
- package/tests/authTranslations.test.js +0 -74
- package/tests/chart-api-census.test.js +0 -366
- package/tests/chartAxisTickBand.test.jsx +0 -95
- package/tests/chartDefaults.test.js +0 -902
- package/tests/chartLabels.test.js +0 -50
- package/tests/chartsPalette.test.js +0 -99
- package/tests/chatApi.test.js +0 -48
- package/tests/chatDriverNames.test.jsx +0 -71
- package/tests/chatExports.test.js +0 -3
- package/tests/chatList.test.jsx +0 -84
- package/tests/chatPicker.test.jsx +0 -82
- package/tests/chatSocket.test.jsx +0 -26
- package/tests/chatThread.test.jsx +0 -116
- package/tests/chatTranslations.test.js +0 -47
- package/tests/chatWorkspace.test.jsx +0 -234
- package/tests/checkKitIntegration.test.jsx +0 -219
- package/tests/createAppTheme.test.js +0 -132
- package/tests/createAppThemeDark.test.js +0 -127
- package/tests/createAppThemeLightGuard.test.js +0 -40
- package/tests/createAppThemePageContrast.test.js +0 -108
- package/tests/createAppThemeTypography.test.js +0 -53
- package/tests/errorCallSiteGuard.test.js +0 -32
- package/tests/exportChart.test.js +0 -313
- package/tests/feedApi.test.js +0 -46
- package/tests/fixtures/light-theme-baseline.json +0 -2234
- package/tests/i18nAggregate.test.js +0 -120
- package/tests/i18nGermanVariant.test.js +0 -65
- package/tests/loginPageErrorResolution.test.jsx +0 -102
- package/tests/messagingApi.test.js +0 -32
- package/tests/messagingChunk6.test.jsx +0 -116
- package/tests/messagingCompactBubble.test.jsx +0 -64
- package/tests/messagingComposer.test.jsx +0 -136
- package/tests/messagingComposerChunk5.test.jsx +0 -113
- package/tests/messagingContractConformance.test.js +0 -69
- package/tests/messagingDirectMessageLauncher.test.jsx +0 -151
- package/tests/messagingExports.test.js +0 -21
- package/tests/messagingInteractions.test.jsx +0 -136
- package/tests/messagingLastMessagePreview.test.jsx +0 -93
- package/tests/messagingLinkify.test.jsx +0 -51
- package/tests/messagingMessageActions.test.jsx +0 -163
- package/tests/messagingMsg6.test.jsx +0 -105
- package/tests/messagingMsg6f.test.jsx +0 -155
- package/tests/messagingMsg6g.test.jsx +0 -166
- package/tests/messagingMsg6h.test.jsx +0 -136
- package/tests/messagingMsg6i.test.jsx +0 -129
- package/tests/messagingPollRendering.test.jsx +0 -142
- package/tests/messagingReactionMerge.test.jsx +0 -77
- package/tests/messagingReadTicksTooltip.test.jsx +0 -36
- package/tests/messagingThreadReceipts.test.jsx +0 -178
- package/tests/messagingThreadingQuoting.test.jsx +0 -87
- package/tests/messagingUnreadLifecycle.test.jsx +0 -78
- package/tests/notificationsApi.test.js +0 -41
- package/tests/notificationsExports.test.js +0 -34
- package/tests/onboardingDescriptors.test.js +0 -132
- package/tests/packageTreeShaking.test.js +0 -126
- package/tests/realtime.test.jsx +0 -219
- package/tests/resolveErrorText.test.js +0 -72
- package/tests/stepSelection.test.js +0 -53
- package/tests/themeCompleteness.test.js +0 -626
- package/tests/timeSeriesLegend.test.js +0 -99
- package/tests/userScreenTranslations.test.jsx +0 -218
- package/tsconfig.build.json +0 -18
- package/vite.config.mjs +0 -6
- package/work-orders/AUTH-1.md +0 -74
- package/work-orders/AUTH-2.md +0 -74
- package/work-orders/AUTH-4.md +0 -183
- package/work-orders/AUTH-5.md +0 -154
- package/work-orders/AUTH-7.md +0 -181
- package/work-orders/AUTH-8.md +0 -184
- package/work-orders/CHART-1.md +0 -285
- package/work-orders/CHART-2.md +0 -222
- package/work-orders/CHART-3.md +0 -163
- package/work-orders/CHART-4.md +0 -203
- package/work-orders/CHART-5.md +0 -226
- package/work-orders/CHART-6.md +0 -428
- package/work-orders/CHART-7.md +0 -175
- package/work-orders/DX-1.md +0 -169
- package/work-orders/DX-2.md +0 -188
- package/work-orders/DX-3.md +0 -195
- package/work-orders/I18N-1.md +0 -254
- package/work-orders/I18N-3.md +0 -207
- package/work-orders/MSG-3.md +0 -375
- package/work-orders/MSG-3b.md +0 -1002
- package/work-orders/MSG-3c.md +0 -378
- package/work-orders/MSG-3d.md +0 -268
- package/work-orders/MSG-3e.md +0 -164
- package/work-orders/MSG-3f.md +0 -391
- package/work-orders/MSG-6e.md +0 -308
- package/work-orders/MSG-6f.md +0 -214
- package/work-orders/MSG-6g.md +0 -244
- package/work-orders/MSG-6h.md +0 -238
- package/work-orders/MSG-6i.md +0 -271
- package/work-orders/MSG-6j.md +0 -117
- package/work-orders/NOTIF-12.md +0 -214
- package/work-orders/NOTIF-13.md +0 -142
- package/work-orders/NOTIF-14.md +0 -151
- package/work-orders/PRIM-1.md +0 -177
- package/work-orders/SHELL-1.md +0 -255
- package/work-orders/SHELL-2.md +0 -197
- package/work-orders/SHELL-3.md +0 -359
- package/work-orders/SHELL-4.md +0 -351
- package/work-orders/SHELL-5.md +0 -345
- package/work-orders/SHELL-6.md +0 -210
- package/work-orders/THEME-1.md +0 -587
- package/work-orders/THEME-10.md +0 -303
- package/work-orders/THEME-11.md +0 -208
- package/work-orders/THEME-2.md +0 -339
- package/work-orders/THEME-3.md +0 -210
- package/work-orders/THEME-4.md +0 -271
- package/work-orders/THEME-5.md +0 -341
- package/work-orders/THEME-6.md +0 -247
- package/work-orders/THEME-7.md +0 -82
- package/work-orders/THEME-8.md +0 -211
- package/work-orders/THEME-9.md +0 -194
- package/work-orders/UCM-AUTH-10.md +0 -490
- package/work-orders/UCM-AUTH-11.md +0 -185
- package/work-orders/UCM-AUTH-12.md +0 -98
- package/work-orders/UCM-AUTH-13.md +0 -47
- package/work-orders/UCM-AUTH-9.md +0 -207
- package/work-orders/UCM-CHART-10.md +0 -150
- package/work-orders/UCM-CHART-11.md +0 -132
- package/work-orders/UCM-CHART-12.md +0 -348
- package/work-orders/UCM-CHART-13.md +0 -122
- package/work-orders/UCM-CHART-14.md +0 -198
- package/work-orders/UCM-CHART-15.md +0 -187
- package/work-orders/UCM-CHART-16.md +0 -169
- package/work-orders/UCM-CHART-17.md +0 -195
- package/work-orders/UCM-CHART-18.md +0 -200
- package/work-orders/UCM-CHART-8.md +0 -147
- package/work-orders/UCM-CHART-9.md +0 -265
- package/work-orders/UCM-CHAT-1.md +0 -190
- package/work-orders/UCM-CHAT-2.md +0 -75
- package/work-orders/UCM-DEP-1.md +0 -63
- package/work-orders/UCM-I18N-4.md +0 -226
- package/work-orders/UCM-I18N-5.md +0 -211
- package/work-orders/UCM-MSG-20.md +0 -192
- package/work-orders/UCM-PRIM-2.md +0 -114
- package/work-orders/UCM-SHELL-7.md +0 -134
- package/work-orders/UCM-SHELL-8.md +0 -125
- package/work-orders/UCM-TEST-1.md +0 -304
- package/work-orders/UCM-THEME-13.md +0 -69
- package/work-orders/UCM-THEME-14.md +0 -312
- package/work-orders/UCM-THEME-15.md +0 -356
- package/work-orders/UCM-THEME-16.md +0 -80
- package/work-orders/UCM-THEME-17.md +0 -111
- package/work-orders/UCM-THEME-18.md +0 -184
- package/work-orders/assets/AUTH-4-user-list-card.html +0 -407
- package/work-orders/assets/PRIM-1-dashboard-primitives.html +0 -624
- package/work-orders/assets/SHELL-2-account-navigation.html +0 -1159
- package/work-orders/assets/THEME-1-baseline-reference-sheet.html +0 -1352
- package/work-orders/assets/UCM-CHAT-1-ai-chat.html +0 -447
- package/work-orders/assets/UCM-THEME-13-dark-prototype.html +0 -390
- package/work-orders/assets/UCM-THEME-17-type-scale.html +0 -391
package/work-orders/SHELL-1.md
DELETED
|
@@ -1,255 +0,0 @@
|
|
|
1
|
-
# WORK ORDER SHELL-1 (ui-core-micha) — a shared user menu: avatar, profile, logout
|
|
2
|
-
|
|
3
|
-
**EXECUTION DIRECTIVE.** If you are the implementer reading this as your own spec, this section is not
|
|
4
|
-
addressed to you — it tells the Orchestrator how to invoke you; you ARE that invocation, do not shell
|
|
5
|
-
out to `codex exec`. Orchestrator: implement through `codex exec` in the background, invoked **directly
|
|
6
|
-
via Bash** (never the `debugger`/`*_coder` Agent wrappers) with **both** flags `--skip-git-repo-check`
|
|
7
|
-
and `--dangerously-bypass-approvals-and-sandbox`, prompt passed as a positional argument from this
|
|
8
|
-
file. Fall back to direct Claude implementation only on Codex quota / rate-limit / non-zero exit.
|
|
9
|
-
|
|
10
|
-
Feature-level WO (Expertenchat envelope). New prefix `SHELL-*` for shared application-shell surfaces
|
|
11
|
-
(header chrome, user menu) — distinct from `MSG-*` (messaging) and `NOTIF-*` (notification domain).
|
|
12
|
-
Design settled with the operator 2026-08-04 against an interactive prototype.
|
|
13
|
-
|
|
14
|
-
## TIER
|
|
15
|
-
Tier 2 — shared-core UI consumed by every app, and it touches the logout path. Independent `reviewer`
|
|
16
|
-
mandatory, `ui_reviewer` mandatory.
|
|
17
|
-
|
|
18
|
-
## WHY
|
|
19
|
-
|
|
20
|
-
Measured across the estate 2026-08-04, not estimated:
|
|
21
|
-
|
|
22
|
-
| App | Account + logout controls today |
|
|
23
|
-
|---|---|
|
|
24
|
-
| spesix `Header.jsx` | account link `:184` + separate logout `:224` — **and the same pair again** at `:269`/`:307` for mobile |
|
|
25
|
-
| survey_app `Header.jsx` | account nav entry `:67`, logout desktop `:152`, logout mobile `:90` |
|
|
26
|
-
| jg-ferien `HeaderUserActions.jsx` | avatar → `/account` only; **logout exists nowhere in the header** — it sits at the bottom of `/more` |
|
|
27
|
-
| hram | **unknown** — no header file under `components/`, different structure |
|
|
28
|
-
|
|
29
|
-
**Seven render sites across two apps for two adjacent actions**, and the duplication is worse *within*
|
|
30
|
-
each app than between them: desktop and mobile variants render the same logout separately. That is
|
|
31
|
-
where behaviour drifts.
|
|
32
|
-
|
|
33
|
-
This is a **consolidation**, not a bug fix. jg's missing header logout is the most visible symptom, but
|
|
34
|
-
fixing only jg would leave the duplication everywhere else untouched.
|
|
35
|
-
|
|
36
|
-
## THE BOUNDARY — settled, do not renegotiate
|
|
37
|
-
|
|
38
|
-
| | |
|
|
39
|
-
|---|---|
|
|
40
|
-
| **ucm owns** | the avatar, the menu, **Profil** (`/account`), **Abmelden** |
|
|
41
|
-
| **Host passes** | account-related entries only, already permission-filtered and already translated |
|
|
42
|
-
| **Stays out** | the context/structure picker, and management navigation such as org administration |
|
|
43
|
-
|
|
44
|
-
**The context picker must never enter this menu.** Verified: spesix's `activeSchoolId` is consumed by
|
|
45
|
-
**13 files** (`ApprovalsPage`, `BudgetsPage`, `ClaimsPage`, `ClaimEditPage`, `AppLayout`, …) and jg's
|
|
46
|
-
`selectedEventId` by **18**. Changing it re-scopes the entire application's data. It is a primary
|
|
47
|
-
control that must stay permanently visible next to the content it governs — burying a control that
|
|
48
|
-
determines *which school's budgets you are reading* behind avatar → menu → item is both two taps too
|
|
49
|
-
many and the wrong mental model. The menu answers "who am I"; the picker answers "what am I looking at".
|
|
50
|
-
|
|
51
|
-
Operator, 2026-08-04: org/structure pickers are app-specific and already solved where they live. Adding
|
|
52
|
-
a second route to them here would be exactly the duplication this WO exists to remove.
|
|
53
|
-
|
|
54
|
-
## SCOPE
|
|
55
|
-
|
|
56
|
-
**A. `UserMenu` — a new exported component.**
|
|
57
|
-
|
|
58
|
-
Trigger is an avatar; clicking opens a menu containing an identity block (name, email), **Profil**,
|
|
59
|
-
any host entries, a separator, and **Abmelden** last.
|
|
60
|
-
|
|
61
|
-
- **Navigation follows the existing `NotificationBell({ resolveLink })` pattern**
|
|
62
|
-
(`notifications/NotificationBell.jsx:19,31`) — the host passes its `navigate`; ucm knows no routes.
|
|
63
|
-
Do not invent a second navigation mechanism.
|
|
64
|
-
- **`/account` is the Profil default.** Verified identical in jg-ferien, spesix, survey_app and hram.
|
|
65
|
-
Overridable, but the default must work with no host configuration.
|
|
66
|
-
- **Abmelden calls ucm's own `logout`** (`auth/AuthContext.jsx:132`) — already there, unexported to any
|
|
67
|
-
UI today. That is the whole gap.
|
|
68
|
-
|
|
69
|
-
**B. ucm owns the avatar.** ucm currently has **no** avatar component (only MUI `Avatar` usage inside
|
|
70
|
-
`ConversationList`); jg has its own local `UserAvatar`. Build ucm's, deriving initials from
|
|
71
|
-
`first_name` / `last_name` / `username`, which `mapUserFromApi` (`auth/AuthContext.jsx:41-56`) already
|
|
72
|
-
carries in every app. Allow a host override for a real image, but the no-config path must render
|
|
73
|
-
something correct.
|
|
74
|
-
|
|
75
|
-
jg's local `UserAvatar` becomes redundant. **Removing it is jg's job, not this WO's** — note it in the
|
|
76
|
-
completion note so the follow-up is written.
|
|
77
|
-
|
|
78
|
-
**C. The host extension point.**
|
|
79
|
-
|
|
80
|
-
```jsx
|
|
81
|
-
items={[{ id, label, onSelect }]}
|
|
82
|
-
```
|
|
83
|
-
|
|
84
|
-
Three rules, each load-bearing:
|
|
85
|
-
|
|
86
|
-
1. **ucm never evaluates permissions.** jg's org entry is gated on `canManageStructure(user)`, a
|
|
87
|
-
jg-local helper. A `requiresPermission` prop would need a permission model shared across four apps —
|
|
88
|
-
there is none, and inventing one here is out of scope. **The host filters, then passes.**
|
|
89
|
-
2. **Labels arrive as resolved strings, not i18n keys.** `More.NOTIFICATIONS` lives in jg's catalogue;
|
|
90
|
-
ucm cannot translate it. This is the same ownership question `django-core-micha` MSG-13 is currently
|
|
91
|
-
failing — dcm emits keys nobody has a catalogue for. Get it right here from the start: **whoever
|
|
92
|
-
owns the text supplies it finished.**
|
|
93
|
-
3. **One action mechanism, not two.** `onSelect` only; the host closes over its own `navigate`. Do not
|
|
94
|
-
also accept `href` — two ways to express the same thing is two things to test and two ways to be
|
|
95
|
-
inconsistent.
|
|
96
|
-
|
|
97
|
-
**Ordering belongs to ucm.** Host entries render as one group in a fixed slot; **Abmelden is always
|
|
98
|
-
last**. If hosts could order freely, logout would sit in four different places and the consistency that
|
|
99
|
-
motivates this WO would be gone.
|
|
100
|
-
|
|
101
|
-
**Expected usage:** spesix and survey_app pass **nothing** — `<UserMenu resolveLink={navigate} />` is
|
|
102
|
-
the whole integration. Only jg passes an entry (its notification settings, which no other app has).
|
|
103
|
-
|
|
104
|
-
**D. Icons — decide once, state it.** jg's entries carry a trailing `ChevronRightIcon` and no leading
|
|
105
|
-
icon; ucm's built-ins would want leading icons. A mixed set looks broken. Either every entry may carry
|
|
106
|
-
an optional leading icon (ucm supplies its own), or none do. **This is the implementer's call, but it
|
|
107
|
-
must be stated, not left to emerge.**
|
|
108
|
-
|
|
109
|
-
**E. The preview toggle from `django-core-micha` MSG-13 scope E.** MSG-13 rules that the push shows
|
|
110
|
-
sender + message text, with a per-user opt-out. dcm ships the preference; **the `Switch` belongs in
|
|
111
|
-
`NotificationSettings.jsx` and is not deliverable from dcm.** It is folded in here because it is the
|
|
112
|
-
same corner of ucm and the same release.
|
|
113
|
-
|
|
114
|
-
Depends on dcm publishing the preference field first. **If it has not landed, ship A–D without E and
|
|
115
|
-
say so** — do not block the menu on it.
|
|
116
|
-
|
|
117
|
-
## CONTEXT PACKAGE — verified current state (Orchestrator, Implementation map)
|
|
118
|
-
|
|
119
|
-
Work from this package; do not explore broadly from scratch — open only the named files to verify.
|
|
120
|
-
If you must dig deeper, delegate to a read-only Explore sub-agent (Haiku).
|
|
121
|
-
|
|
122
|
-
**New file: `src/auth/UserMenu.jsx`.** Sits with `AuthContext.jsx` (identity/auth surface), not
|
|
123
|
-
`notifications/` — this is not a notification. Export it in `src/index.js` next to the existing auth
|
|
124
|
-
block (`export { AuthContext, AuthProvider } from './auth/AuthContext';` at `:4`) — add
|
|
125
|
-
`export { UserMenu } from './auth/UserMenu';` there, not in the notifications block at `:59-65`.
|
|
126
|
-
|
|
127
|
-
**Menu pattern to mirror — `src/notifications/NotificationBell.jsx` (whole file, 85 lines), exactly:**
|
|
128
|
-
- `resolveLink` prop shape (`:19`): `export function NotificationBell({ resolveLink }) { … }`. The
|
|
129
|
-
handler calls `resolveLink(someLinkString)` conditionally (`:31`) — same contract `UserMenu` must
|
|
130
|
-
use: `resolveLink('/account')` for Profil, `resolveLink(item.onSelect...)` is wrong per spec —
|
|
131
|
-
re-read scope C: host items use `onSelect` (a callback), NOT `resolveLink` — `resolveLink` is only
|
|
132
|
-
for ucm's own Profil navigation. Two distinct mechanisms coexist here (ucm's own nav via
|
|
133
|
-
`resolveLink`, host items via their own `onSelect`) and that is correct, not a violation of "one
|
|
134
|
-
action mechanism" (point C.3 bars the host from having *two* ways — `onSelect` is the host's one way).
|
|
135
|
-
- Trigger + `Menu` scaffold (`:36-51`): `IconButton` with `aria-label`, `onClick={(e) =>
|
|
136
|
-
setAnchorEl(e.currentTarget)}`, then MUI `<Menu anchorEl={anchorEl} open={Boolean(anchorEl)}
|
|
137
|
-
onClose={() => setAnchorEl(null)} anchorOrigin={{horizontal:'right',vertical:'bottom'}}
|
|
138
|
-
transformOrigin={{horizontal:'right',vertical:'top'}}>`. **MUI `Menu` handles Escape and
|
|
139
|
-
click-outside natively via its built-in focus trap** (`onClose` fires for both) — no custom
|
|
140
|
-
keyboard/focus-trap code needed; `ui_reviewer`'s RISKS check is about *not breaking* this default,
|
|
141
|
-
not building one. Focus returns to the trigger `IconButton` automatically on close (MUI default);
|
|
142
|
-
verify this in the required test rather than assuming it.
|
|
143
|
-
- Item click closes the menu (`setAnchorEl(null)`) before/alongside the action (`:28-32`) — Abmelden
|
|
144
|
-
and Profil and each host item must all close the menu on click.
|
|
145
|
-
|
|
146
|
-
**Identity data — `src/auth/AuthContext.jsx`:**
|
|
147
|
-
- `mapUserFromApi` (`:41-73`) is where `user.first_name`, `user.last_name`, `user.username`,
|
|
148
|
-
`user.email` land — confirmed present on every `user` object in every app (already relied on by
|
|
149
|
-
`AccountPage`). Avatar initials: prefer `first_name[0]+last_name[0]`, fall back to `username[0]`
|
|
150
|
-
when names are absent (per scope B) — no other field exists to derive from.
|
|
151
|
-
- `logout` (`:132-141`): `const logout = async () => { try { await logoutSession(); } catch (e) {
|
|
152
|
-
console.error(...) } finally { setUser(null); } }`, already exposed on the context value (`:150`).
|
|
153
|
-
- **No `useAuth` hook exists in this repo** — every consumer does `useContext(AuthContext)` directly
|
|
154
|
-
(`AuthContext` exported at `:15`, `createContext(null)`). `UserMenu` must do the same — do not
|
|
155
|
-
invent a `useAuth` hook as part of this WO, that would be scope creep beyond the menu itself.
|
|
156
|
-
- Do not touch any line in this file (NON-GOALS already says so) — `UserMenu` only *reads*
|
|
157
|
-
`user`/`logout` off the context.
|
|
158
|
-
|
|
159
|
-
**Avatar:** no existing ucm `Avatar` component (verified — only bare MUI `<Avatar>` usage inside
|
|
160
|
-
`ConversationList`, nothing reusable). Build it inline in `UserMenu.jsx` or as a small
|
|
161
|
-
`src/auth/UserAvatar.jsx` sibling — implementer's call; MUI's `<Avatar>{initials}</Avatar>` for the
|
|
162
|
-
no-image case, `<Avatar src={overrideImageUrl} />` when a host passes one (scope B: "Allow a host
|
|
163
|
-
override for a real image").
|
|
164
|
-
|
|
165
|
-
**i18n — new file `src/i18n/userMenuTranslations.ts`**, same shape as the existing four
|
|
166
|
-
(`src/i18n/notificationsTranslations.ts` is the closest analog, e.g. its `:1-4`): a flat object,
|
|
167
|
-
keys like `'UserMenu.PROFILE'`/`'UserMenu.LOGOUT'`, each `{ de, fr, en, sw }`. **No existing
|
|
168
|
-
`UserMenu.*` or reusable `Profil`/`Abmelden` key exists yet** — `authTranslations.ts` has
|
|
169
|
-
`Account.TAB_PROFILE` (`:1616-1619`, "Profil"/"Profile") which is close but is the *account page
|
|
170
|
-
tab* label, a different UI surface; do not reuse it silently — either add fresh `UserMenu.*` keys
|
|
171
|
-
(recommended, keeps this component's translations self-contained and independently consumable) or
|
|
172
|
-
explicitly reuse `Account.TAB_PROFILE` if the copy is identical — state which was chosen. Then export
|
|
173
|
-
`userMenuTranslations` from `src/index.js` next to `authTranslations` (`:56`)/`notificationsTranslations`.
|
|
174
|
-
Per scope C.2, host-supplied `items[].label` are already-resolved strings — `UserMenu` must NOT run
|
|
175
|
-
them through `t()`.
|
|
176
|
-
|
|
177
|
-
**Package/test conventions:** flat package, `src/` at repo root (no `frontend/` subdir), React 19 +
|
|
178
|
-
MUI 7 as peer deps (`package.json`), Vitest + `@testing-library/react`. New test file
|
|
179
|
-
`tests/UserMenu.test.jsx` mirroring `tests/NotificationBell.test.jsx`'s shape: `vi.hoisted()` mocks,
|
|
180
|
-
stub `react-i18next`'s `useTranslation` with a **stable** `t` reference (module-level, not recreated
|
|
181
|
-
per render — the NOTIF-14 postmortem in this repo's own `WORK_ORDERS.md` documents exactly this
|
|
182
|
-
class of bug: an unstable mocked `t` retriggers effects and clobbers state in tests), and
|
|
183
|
-
`afterEach(cleanup)`.
|
|
184
|
-
|
|
185
|
-
## NON-GOALS / DO NOT TOUCH
|
|
186
|
-
- **No context or structure picker**, in any form, including read-only display of the current context.
|
|
187
|
-
ucm cannot know whether the unit is a school, an event, a course or a department.
|
|
188
|
-
- No management navigation (org administration and the like) — account-related entries only.
|
|
189
|
-
- Do not change `AuthContext`'s `logout`, session handling, or `mapUserFromApi`.
|
|
190
|
-
- Do not touch any host app in this WO. The four header rewires are separate small WOs, one per app.
|
|
191
|
-
- Do not change `NotificationBell` or the notification feed.
|
|
192
|
-
- Do not add a permission model, a routing table, or an i18n catalogue to ucm.
|
|
193
|
-
|
|
194
|
-
## RISKS
|
|
195
|
-
- **Profil goes from one tap to two** in every app, including the three whose avatar is a direct link
|
|
196
|
-
today. On mobile that is felt. It is the price of the consolidation and must be stated in the
|
|
197
|
-
completion note, not discovered by users.
|
|
198
|
-
- **The benefit only materialises per app.** ucm exports nothing header-shaped today, so there is no
|
|
199
|
-
single place to switch over — the component lands, then four hosts adopt it individually.
|
|
200
|
-
- **"Looks universal" is not a check.** An earlier version of the prototype had *Benachrichtigungen* as
|
|
201
|
-
a ucm built-in. In fact **only jg** embeds `NotificationSettings`, and `?tab=notifications` exists
|
|
202
|
-
only there — three apps would have got a menu entry pointing at a route they do not have. Verify
|
|
203
|
-
every built-in against all consuming apps before making it a built-in.
|
|
204
|
-
- **hram is unverified.** Do not claim four apps benefit until someone has looked at hram's shell.
|
|
205
|
-
- A menu is a focus trap if built carelessly: keyboard operation, `Escape`, click-outside and focus
|
|
206
|
-
return to the trigger all have to work. `ui_reviewer` should check this specifically.
|
|
207
|
-
|
|
208
|
-
## REQUIRED TESTS TO WRITE
|
|
209
|
-
Narrow and behavioural. Do NOT run the full suite.
|
|
210
|
-
|
|
211
|
-
1. With no `items` and no overrides, the menu renders identity, Profil and Abmelden — the zero-config
|
|
212
|
-
path two of four apps will use.
|
|
213
|
-
2. Abmelden calls `AuthContext`'s `logout`. Assert the call, not merely that the item rendered.
|
|
214
|
-
3. Profil navigates via `resolveLink` to `/account` by default, and to an override when given.
|
|
215
|
-
4. Host `items` render in their slot with their `onSelect` invoked on click — and **Abmelden is still
|
|
216
|
-
the last item** with host entries present. That ordering assertion is the guard against hosts
|
|
217
|
-
drifting apart.
|
|
218
|
-
5. Keyboard: the trigger opens the menu, `Escape` closes it and returns focus to the trigger.
|
|
219
|
-
6. The avatar renders correct initials from `first_name`/`last_name`, and falls back to `username` when
|
|
220
|
-
names are absent.
|
|
221
|
-
|
|
222
|
-
**Non-vacuity:** test 4's ordering assertion must fail if host entries are appended after Abmelden;
|
|
223
|
-
test 2 must fail if `logout` is stubbed out.
|
|
224
|
-
|
|
225
|
-
## TEST SCOPE FOR THE GATE (orchestrator)
|
|
226
|
-
The new component's tests plus whatever covers `AuthContext` and `NotificationSettings` if scope E is
|
|
227
|
-
included. Not the full suite.
|
|
228
|
-
|
|
229
|
-
## TARGET REPO
|
|
230
|
-
`C:\Users\biglmi\Documents\webapps\ui-core-micha`. Branch `main` (or `develop` if present). Publish per
|
|
231
|
-
the repo's release flow; host pin bumps and header rewires are separate work.
|
|
232
|
-
|
|
233
|
-
## MINI-HANDOVER (pastable)
|
|
234
|
-
|
|
235
|
-
> Repo: `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`, or `develop` if present).
|
|
236
|
-
> Work order: `work-orders/SHELL-1.md` — read it fully, then follow the `orchestrate-codex` skill.
|
|
237
|
-
>
|
|
238
|
-
> **Design is settled against an interactive prototype — do not renegotiate the boundary.** ucm owns the
|
|
239
|
-
> avatar, the menu, Profil (`/account`) and Abmelden. The host passes only account-related entries,
|
|
240
|
-
> already permission-filtered and already translated. **The context/structure picker never enters this
|
|
241
|
-
> menu** — spesix's `activeSchoolId` drives 13 files and jg's `selectedEventId` 18; it re-scopes the
|
|
242
|
-
> whole app and must stay a permanently visible control of its own.
|
|
243
|
-
>
|
|
244
|
-
> Two traps, both already paid for elsewhere in this estate: **do not make an entry a built-in without
|
|
245
|
-
> verifying it in every app** (an earlier prototype had Benachrichtigungen as shared — only jg has it),
|
|
246
|
-
> and **labels arrive as finished strings, never i18n keys** (dcm MSG-13 is currently broken for exactly
|
|
247
|
-
> that reason).
|
|
248
|
-
>
|
|
249
|
-
> Expected integration for spesix and survey_app is `<UserMenu resolveLink={navigate} />` and nothing
|
|
250
|
-
> else. Scope E depends on dcm MSG-13's preference landing — if it has not, ship A–D and say so.
|
|
251
|
-
|
|
252
|
-
## PROGRESS CONTRACT
|
|
253
|
-
Emit `PLAN: <steps>` up front, then a single-line `PROGRESS: [<n>/<total>] <action>` before every
|
|
254
|
-
relevant action and `PROGRESS: [<n>/<total>] done` on completion, spaced so no gap exceeds ~2 min,
|
|
255
|
-
stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>`.
|
package/work-orders/SHELL-2.md
DELETED
|
@@ -1,197 +0,0 @@
|
|
|
1
|
-
# SHELL-2 — AccountPage: from a horizontal tab strip to a grouped sidebar + mobile drawer
|
|
2
|
-
|
|
3
|
-
**Target repo:** `ui-core-micha` (branch `main` — this repo has no `develop`)
|
|
4
|
-
**Tier:** 2 (shared core)
|
|
5
|
-
**Review:** independent `reviewer` (Sonnet, full) **and** `ui_reviewer` — spawned concurrently, both mandatory before commit
|
|
6
|
-
**Prototype (visual spec):** [`work-orders/assets/SHELL-2-account-navigation.html`](assets/SHELL-2-account-navigation.html)
|
|
7
|
-
|
|
8
|
-
---
|
|
9
|
-
|
|
10
|
-
## A. Envelope
|
|
11
|
-
|
|
12
|
-
### Goal
|
|
13
|
-
|
|
14
|
-
Make `AccountPage` usable on a 375 px viewport, and give the account surface the same
|
|
15
|
-
navigation pattern the estate already uses in jg-ferien's `EventInfoPage`.
|
|
16
|
-
|
|
17
|
-
Expected outcome: the horizontal tab strip is gone. On desktop the sections live in a
|
|
18
|
-
sticky, grouped sidebar; on mobile they live in a bottom drawer opened by an in-page
|
|
19
|
-
trigger bar. The users section renders cards instead of a table below `md`.
|
|
20
|
-
|
|
21
|
-
### Measured evidence (2026-08-08, live at 375 px)
|
|
22
|
-
|
|
23
|
-
Measured in a running cockpit (which mounts ucm's `AccountPage` at `/account`), with the
|
|
24
|
-
host header neutralised so the numbers describe ucm alone:
|
|
25
|
-
|
|
26
|
-
- All six sections render without document overflow — `AccountPage` itself does **not**
|
|
27
|
-
break the layout at 375 px.
|
|
28
|
-
- The tab strip: scroller `clientWidth` 343 vs `scrollWidth` 589, `overflow-x: auto`,
|
|
29
|
-
246 px of scroll travel, and **`scrollButtons: 0`**. At rest, Profil / Sicherheit /
|
|
30
|
-
Benutzer / Einladen are reachable; Support and the consumer-injected section are off
|
|
31
|
-
screen with no arrow, no fade, no hint that they exist. This is a discoverability
|
|
32
|
-
failure, not a reachability failure — the tabs do respond to a horizontal swipe.
|
|
33
|
-
- The users table: 1045 px of content inside a 341 px `MuiTableContainer` with
|
|
34
|
-
`overflow-x: auto`. One third is visible. The `Aktionen` column sits roughly 700 px to
|
|
35
|
-
the right. Column `minWidth` values: E-Mail 220, Name 180, Neu 90, Letzte Anmeldung 120,
|
|
36
|
-
Rolle 180, Aktionen 220.
|
|
37
|
-
- Interactive controls on the auth pages measure 34–36 px tall, below the 44 px touch
|
|
38
|
-
target guideline. In scope only where this WO touches the control anyway.
|
|
39
|
-
|
|
40
|
-
### Scope
|
|
41
|
-
|
|
42
|
-
**A. Section navigation — both halves of the jg-ferien pattern**
|
|
43
|
-
(reference: `jg-ferien/frontend/src/components/EventInfoHub/SectionSwitcher.jsx`,
|
|
44
|
-
driven from `jg-ferien/frontend/src/pages/EventInfoPage.jsx:1126-1159`)
|
|
45
|
-
|
|
46
|
-
- **`md` and up:** a CSS grid `280px minmax(0, 1fr)`. Left, a sticky vertical section list
|
|
47
|
-
grouped under headings — per group an outlined `Paper` with a heading row and a `List` of
|
|
48
|
-
`ListItemButton`, the active entry in the `selected` state. Right, the section content
|
|
49
|
-
with `minWidth: 0`.
|
|
50
|
-
- **Below `md`:** the content spans the full width. The grouped list moves into a bottom
|
|
51
|
-
`Drawer`: top corners rounded 18 px, `maxHeight: 78dvh`, bottom padding
|
|
52
|
-
`max(16px, env(safe-area-inset-bottom))`, a title row, list scrolls inside.
|
|
53
|
-
- **The trigger** — the part the reference does not supply. In jg-ferien the button that
|
|
54
|
-
opens the drawer lives in that app's own page header; `AccountPage` has no header of its
|
|
55
|
-
own (the consuming app provides it), so the trigger must live inside `AccountPage`. Per
|
|
56
|
-
the prototype: a full-width 56 px bar at the top of the content, showing a small "Bereich"
|
|
57
|
-
caption above the current section name, with a trailing chevron.
|
|
58
|
-
|
|
59
|
-
**B. Grouping, and the `extraTabs` extension**
|
|
60
|
-
|
|
61
|
-
- Fixed groups owned by ucm, in this order: `Mein Konto` (profile, security) ·
|
|
62
|
-
`Verwaltung` (users, invite) · `Hilfe` (support) · `Weitere` (catch-all, last).
|
|
63
|
-
- `extraTabs` entries gain an **optional** `group` field. An entry without `group` falls
|
|
64
|
-
into `Weitere`. Every existing call site keeps working unchanged — this is additive only.
|
|
65
|
-
|
|
66
|
-
**C. Users section: table to cards below `md`**
|
|
67
|
-
|
|
68
|
-
- At `md` and up the table stays exactly as it is, columns and `minWidth` values unchanged.
|
|
69
|
-
- Below `md`, one card per user carrying the same fields as a row — email, name, the "Neu"
|
|
70
|
-
flag, last login, role, actions — with the actions reachable without horizontal scrolling
|
|
71
|
-
and with touch targets of at least 44 px.
|
|
72
|
-
|
|
73
|
-
**D. Version**
|
|
74
|
-
|
|
75
|
-
- Bump to `2.30.0`. Minor rather than patch because `extraTabs` gains a new public field;
|
|
76
|
-
additive API is a minor under semver.
|
|
77
|
-
|
|
78
|
-
### Non-goals / do not touch
|
|
79
|
-
|
|
80
|
-
- Pagination or filtering for the user list. Absent today, absent in the prototype,
|
|
81
|
-
explicitly not part of this WO — do not add it "while in there".
|
|
82
|
-
- The internal content of the Profil, Sicherheit, Einladen, Support and consumer-injected
|
|
83
|
-
sections. Only their placement in the navigation changes.
|
|
84
|
-
- The access-code, QR-signup and invite management components.
|
|
85
|
-
- The six auth pages (Login, SignUp, SignupConfirm, PasswordChange, PasswordResetRequest,
|
|
86
|
-
PasswordInvite). Measured clean at 375 px; out of scope.
|
|
87
|
-
- Messaging, notifications, charts, onboarding.
|
|
88
|
-
- The consuming apps. No host repo is touched by this WO — in particular **cockpit's header
|
|
89
|
-
is a separate work order**; its toolbar is what inflates the document to 498 px on every
|
|
90
|
-
route, including `/account`, and fixing it here would be out of scope.
|
|
91
|
-
- No behaviour change, no permission change, no data-contract change (parity guardrail).
|
|
92
|
-
|
|
93
|
-
### Replaces / removes — within the prototype's declared coverage
|
|
94
|
-
|
|
95
|
-
The prototype is the visual spec; **this list, not prototype silence, is the removal
|
|
96
|
-
authority.** Everything named here must be gone when the WO is done:
|
|
97
|
-
|
|
98
|
-
1. **The horizontal MUI `Tabs` strip — on desktop as well as mobile.** It is replaced by
|
|
99
|
-
the sidebar (desktop) and the drawer (mobile). Keeping it at any breakpoint means the
|
|
100
|
-
WO is not done. The operator was asked about this specifically and chose both halves.
|
|
101
|
-
2. **On mobile, the section-title heading below the trigger bar.** The trigger bar is the
|
|
102
|
-
sole carrier of the current section name there. Do not re-add it as a "missing" heading.
|
|
103
|
-
Desktop keeps its section heading, because desktop has no trigger bar to carry the name.
|
|
104
|
-
3. The scrollable-tabs affordance question disappears with the strip — do not "fix" it by
|
|
105
|
-
adding scroll buttons or a fade to something that no longer exists.
|
|
106
|
-
|
|
107
|
-
A redesign is a subtraction task. If the finished screen carries more UI than it does
|
|
108
|
-
today, that is a stop signal, not thoroughness.
|
|
109
|
-
|
|
110
|
-
### Deliberately keeps — undrawn in places, but must survive
|
|
111
|
-
|
|
112
|
-
- **The `?tab=<value>` URL contract** (`src/pages/AccountPage.jsx:60`), including the
|
|
113
|
-
fallback to `profile` when the value is unknown *or* not permitted for the user
|
|
114
|
-
(`:180-186`). Cockpit's `/user-management`, `/profile` and `/change-password` redirects
|
|
115
|
-
depend on it. This is the single most breakable thing in the WO.
|
|
116
|
-
- The `?from=recovery` and `?from=weak_login` entry states (`:64-65`).
|
|
117
|
-
- The full `extraTabs` contract (`:146-155`): `value`, `label` as a string **or a function**
|
|
118
|
-
receiving `{ user, perms, isSuperUser, t }`, `visible(context)`, `render`. Extended by
|
|
119
|
-
`group` only; nothing removed, nothing made required.
|
|
120
|
-
- The permission-conditional section list: `users` on `canViewUsers`, `invite` on
|
|
121
|
-
`canViewInvite`, `support` on `isSuperUser || perms.can_view_support`, profile and
|
|
122
|
-
security always (`:127-144`). The section list is per-user and can be as short as two
|
|
123
|
-
entries.
|
|
124
|
-
- `WidePage` as the page container, and its title.
|
|
125
|
-
- The desktop section heading above the content.
|
|
126
|
-
- The users table's column set and `minWidth` values at `md` and up.
|
|
127
|
-
- No standalone "Übersicht" entry above the groups. jg-ferien has one; `AccountPage` has no
|
|
128
|
-
overview screen for it to point at, so none is invented. Navigation starts at the first
|
|
129
|
-
group. Settled with the operator.
|
|
130
|
-
|
|
131
|
-
### Risks
|
|
132
|
-
|
|
133
|
-
- **No staging net.** This repo has no `develop`. A push to `main` that touches `src/**` or
|
|
134
|
-
`package.json` publishes to npm immediately via `.github/workflows/publish.yml`. The
|
|
135
|
-
independent review is the only gate before publication — it is not back-fillable.
|
|
136
|
-
- **Fourteen consumers inherit the desktop change** on their next pin bump. Nobody is
|
|
137
|
-
forced: every consumer pins an exact version (eight sit on 2.4.5). Only cockpit is
|
|
138
|
-
expected to bump soon, and that bump belongs to cockpit's own WO.
|
|
139
|
-
- **`AccountPage` has zero tests today.** None of the 20 files under `tests/` touches it or
|
|
140
|
-
`UserListComponent`. The `?tab=` contract is currently unguarded, so a regression there
|
|
141
|
-
would surface first as three broken redirects in cockpit, silently.
|
|
142
|
-
- **Drawer stacking.** jg-ferien had to raise its own `SectionSwitcher` drawer to
|
|
143
|
-
`theme.zIndex.drawer + 3` to clear its bottom navigation bar. ucm has no bottom nav, but a
|
|
144
|
-
consuming app may — the drawer must not assume it is topmost, and must not hard-code a
|
|
145
|
-
value that fights a host's own layering.
|
|
146
|
-
- **Safe-area insets are inert without `viewport-fit=cover`.** jg-ferien uses
|
|
147
|
-
`env(safe-area-inset-bottom)` while its `index.html` omits `viewport-fit=cover`, so those
|
|
148
|
-
insets resolve to zero there. Copy the padding by all means, but do not assume it is
|
|
149
|
-
doing anything, and do not change any consuming app's viewport meta tag from here.
|
|
150
|
-
|
|
151
|
-
### Tests to write
|
|
152
|
-
|
|
153
|
-
Narrow and new — both files are new; there is nothing to extend. Written as part of the
|
|
154
|
-
implementation, run by the Orchestrator.
|
|
155
|
-
|
|
156
|
-
**`tests/AccountPage.test.jsx`**
|
|
157
|
-
|
|
158
|
-
1. The grouped list renders: the four groups in fixed order, each built-in section under
|
|
159
|
-
its declared group.
|
|
160
|
-
2. `?tab=users` activates the users section.
|
|
161
|
-
3. `?tab=<unknown>` falls back to `profile`.
|
|
162
|
-
4. `?tab=users` for a user **without** `canViewUsers` falls back to `profile` — the
|
|
163
|
-
permission fallback, not just the unknown-value one.
|
|
164
|
-
5. A short permission set (profile + security only) renders a two-entry list without an
|
|
165
|
-
empty `Verwaltung` or `Hilfe` group heading.
|
|
166
|
-
6. `extraTabs` without `group` lands in `Weitere`; with `group: 'Mein Konto'` lands there.
|
|
167
|
-
7. `extraTabs` with a **function** `label` and with `visible()` returning false are both
|
|
168
|
-
still honoured (guards the contract this WO extends).
|
|
169
|
-
8. Below `md`: the trigger bar renders and names the current section; the duplicate section
|
|
170
|
-
heading is **absent** (assert its absence explicitly — this is a removal).
|
|
171
|
-
9. At `md` and up: the sidebar renders and no trigger bar is present.
|
|
172
|
-
|
|
173
|
-
Mock the breakpoint per this estate's established pattern —
|
|
174
|
-
`vi.mock('@mui/material/useMediaQuery')` with a per-test return value, as
|
|
175
|
-
`jg-ferien/frontend/src/components/Header.test.jsx` does.
|
|
176
|
-
|
|
177
|
-
**`tests/UserListComponent.test.jsx`**
|
|
178
|
-
|
|
179
|
-
10. At `md` and up: a table with the six columns.
|
|
180
|
-
11. Below `md`: one card per user, each carrying email, name, the "Neu" flag, last login,
|
|
181
|
-
role and the actions; assert there is no horizontally scrolling container.
|
|
182
|
-
|
|
183
|
-
Prove non-vacuity for at least tests 4 and 8 by temporarily removing the corresponding
|
|
184
|
-
behaviour and confirming the test fails.
|
|
185
|
-
|
|
186
|
-
### Parity guardrail
|
|
187
|
-
|
|
188
|
-
The prototype is the visual and UX spec. Visual/UX only: **no behaviour, no permission, no
|
|
189
|
-
data-contract change.** `ui_reviewer` checks it in both directions — everything in the
|
|
190
|
-
prototype present, and nothing outside it surviving. Because this is a visual redesign,
|
|
191
|
-
before the WO is marked done the Orchestrator asks the operator to run a side-by-side of
|
|
192
|
-
the built screen against the prototype; surviving legacy has repeatedly slipped past a
|
|
193
|
-
static diff review in this estate.
|
|
194
|
-
|
|
195
|
-
### Preconditions
|
|
196
|
-
|
|
197
|
-
None. This WO is independent of cockpit's navigation WO and can land first.
|