@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/CHART-2.md
DELETED
|
@@ -1,222 +0,0 @@
|
|
|
1
|
-
# WORK ORDER CHART-2 (ui-core-micha) — a time-series chart preset with range picker and series toggles
|
|
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). Extends CHART-1. Operator request 2026-08-04 from jg's event
|
|
11
|
-
activity chart; the same controls are wanted wherever a time series is charted, and `django-core-micha`
|
|
12
|
-
ACT-1 makes activity data available to every app.
|
|
13
|
-
|
|
14
|
-
## TIER
|
|
15
|
-
Tier 2 — shared-core UI consumed by every app. Independent `reviewer` + `ui_reviewer` mandatory.
|
|
16
|
-
|
|
17
|
-
## WHY
|
|
18
|
-
|
|
19
|
-
CHART-1 already ships `ChartFrame` (Paper + title + **toolbar slot** + loading / error / empty +
|
|
20
|
-
responsive container + SVG/PNG export + a11y), a themed `BarChart`, `getNeutralChartPalette` and
|
|
21
|
-
`chartsTranslations`. The frame's toolbar slot exists for exactly this and is currently unused by any
|
|
22
|
-
consumer.
|
|
23
|
-
|
|
24
|
-
jg's `ActivitySection.jsx` bypasses the kit entirely (`import { BarChart } from '@mui/x-charts/BarChart'`
|
|
25
|
-
at `:9`) and hand-rolls its own `Paper`, loading, error and empty states. Rather than jg building a
|
|
26
|
-
range picker and series checkboxes locally, they belong in the kit — every app charting a time series
|
|
27
|
-
wants both.
|
|
28
|
-
|
|
29
|
-
## SCOPE
|
|
30
|
-
|
|
31
|
-
**A. A range picker for the toolbar slot.** Presets **1 day / 1 week / 1 month / 1 year** (operator,
|
|
32
|
-
2026-08-04), emitting the selected range to the host. The host owns fetching; the picker owns the choice.
|
|
33
|
-
|
|
34
|
-
The range must also carry the **granularity** the consumer should request — dcm ACT-1's query endpoint
|
|
35
|
-
aggregates server-side, and a year of 4-hour buckets is ~2190 points, which no chart can render
|
|
36
|
-
usefully. A picker that changes the window but not the resolution reproduces exactly the
|
|
37
|
-
unreadable-density problem this WO exists to fix.
|
|
38
|
-
|
|
39
|
-
**The range-to-resolution mapping (operator, 2026-08-04) — implement exactly this:**
|
|
40
|
-
|
|
41
|
-
| Range | Resolution | Points |
|
|
42
|
-
|---|---|---|
|
|
43
|
-
| 1 day | 1 hour | 24 |
|
|
44
|
-
| 1 week | 4 hours | ~42 |
|
|
45
|
-
| 1 month | 1 day | ~30 |
|
|
46
|
-
| 1 year | 1 month | 12 |
|
|
47
|
-
|
|
48
|
-
Every preset lands between a dozen and fifty points, which is what keeps the chart readable at any
|
|
49
|
-
range. **The resolution follows the window; it is not an independent control** and must not be exposed
|
|
50
|
-
as one.
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
**B. Series toggles for the toolbar slot.** Check/uncheck each series independently.
|
|
54
|
-
|
|
55
|
-
**These are not cosmetic.** In jg's chart two series share one y-axis with different units — user counts
|
|
56
|
-
reach 28 while presence-hours sit near zero, so the second series is invisible. Toggling one off
|
|
57
|
-
rescales the axis and makes the other readable. Whether to offer a second y-axis instead is a real
|
|
58
|
-
alternative: **if you do not add one, say so deliberately** rather than leaving it unconsidered.
|
|
59
|
-
|
|
60
|
-
Deselecting every series must leave a stable empty chart — not a crash, not a permanent spinner.
|
|
61
|
-
|
|
62
|
-
**C. Compose them into a preset** on `ChartFrame` + the existing `BarChart`, so a consumer gets frame,
|
|
63
|
-
chart, picker and toggles from one component and passes data plus callbacks.
|
|
64
|
-
|
|
65
|
-
**Presentational only — the host fetches.** Take `data`, the current range and series selection, and
|
|
66
|
-
callbacks; do not call any endpoint. If all four hosts later write the identical fetch against ACT-1's
|
|
67
|
-
endpoint, *that* is the signal to add an adapter — and note the inverse trap from this estate's recent
|
|
68
|
-
history: building the shared thing before two identical consumers exist is how you generalise against a
|
|
69
|
-
single case and get it wrong.
|
|
70
|
-
|
|
71
|
-
## CONTEXT PACKAGE — verified current state (Orchestrator, Implementation map)
|
|
72
|
-
|
|
73
|
-
Work from this package; do not explore broadly from scratch — open only the named files to verify.
|
|
74
|
-
|
|
75
|
-
**New file: `src/components/charts/TimeSeriesChart.jsx`** (generic name — non-goal bars anything
|
|
76
|
-
app-specific; this is not called `ActivityChart`). Export it in `src/index.js` right after the
|
|
77
|
-
existing `LineChart` export (`:46`): `export { TimeSeriesChart } from './components/charts/TimeSeriesChart';`.
|
|
78
|
-
|
|
79
|
-
**`ChartFrame`'s toolbar slot (`src/components/charts/ChartFrame.jsx`)** — the prop is named
|
|
80
|
-
**`toolbar`** (not `toolbarSlot`), destructured `:20`, rendered `:74` inside a `Box` next to the
|
|
81
|
-
title/subtitle, `justifyContent: 'space-between'`. Full prop list `:17-34`:
|
|
82
|
-
`title, subtitle, toolbar, loading, error, isEmpty, emptyMessage, minHeight, aspect, exportOptions,
|
|
83
|
-
onExportSvg, onExportPng, ariaLabel, children, variant, sx`. State precedence `:58-65`:
|
|
84
|
-
`loading → error → isEmpty → children` — `TimeSeriesChart` passes its own `loading`/`error`/`isEmpty`
|
|
85
|
-
straight through, it does not reimplement these.
|
|
86
|
-
|
|
87
|
-
**`BarChart` (`src/components/charts/BarChart.jsx`, 44 lines)** — required props `xAxisLabel`/
|
|
88
|
-
`yAxisLabel` (throws if absent, `:27-29`). `series` is a bare array of MUI X-Charts series objects,
|
|
89
|
-
e.g. `{ data: [...], label, ... }` — no ucm wrapping. Colors: `palette || neutralPalette.categorical`
|
|
90
|
-
(from `useNeutralChartPalette()`), assigned **positionally by index** — series `i` gets
|
|
91
|
-
`categorical[i]`. `hideLegend={series.length <= 1}`.
|
|
92
|
-
|
|
93
|
-
**Data contract for `TimeSeriesChart`** (design decision, state it): the host has already fetched
|
|
94
|
-
and shaped the series (dcm ACT-1's query endpoint returns rolled-up buckets; this component knows
|
|
95
|
-
nothing about that origin). Prop shape:
|
|
96
|
-
```jsx
|
|
97
|
-
<TimeSeriesChart
|
|
98
|
-
title
|
|
99
|
-
xAxisLabel
|
|
100
|
-
yAxisLabel
|
|
101
|
-
data={{ xLabels: [...], series: [{ key: 'users', label: 'Users', data: [...] }, { key: 'presence', label: 'Presence', data: [...] }] }}
|
|
102
|
-
loading
|
|
103
|
-
error
|
|
104
|
-
onRangeChange={(rangeKey, granularity) => {...}} // rangeKey: '1d'|'1w'|'1m'|'1y'
|
|
105
|
-
/>
|
|
106
|
-
```
|
|
107
|
-
Range selection is **self-managed internal state** (default a sensible preset, e.g. `'1w'`), emitting
|
|
108
|
-
`onRangeChange(rangeKey, granularity)` on every change so the host can refetch `data` for the new
|
|
109
|
-
window — the host owns fetching (non-goal), this component owns only which range is currently
|
|
110
|
-
selected and telling the host what changed. Series-toggle visibility is **also self-managed internal
|
|
111
|
-
state** (`Set` of visible series keys, all visible by default) — deselecting is a pure client-side
|
|
112
|
-
filter over already-fetched `data`, no host round-trip needed, so no `onSeriesToggle` callback is
|
|
113
|
-
required (optional to add if a reviewer disagrees, but the WO's own framing — "these are not
|
|
114
|
-
cosmetic... toggling rescales the axis" — describes a display-only operation).
|
|
115
|
-
|
|
116
|
-
**Range-to-granularity mapping — implement exactly, no per-app override:**
|
|
117
|
-
`'1d' → 'hour'`, `'1w' → '4hour'`, `'1m' → 'day'`, `'1y' → 'month'` (match whatever granularity
|
|
118
|
-
vocabulary dcm ACT-1's query endpoint expects once it publishes — since CHART-2 does not fetch, the
|
|
119
|
-
exact string values are this component's own contract, name them clearly, e.g. `'hour' | '4hour' |
|
|
120
|
-
'day' | 'month'`, and state the chosen vocabulary in the completion note so ACT-1/ACT-3 can align).
|
|
121
|
-
|
|
122
|
-
**Range picker widget — decide and state (per WO's own "if you consider X, say so"):** this repo has
|
|
123
|
-
**zero existing `ToggleButtonGroup` usage** (grepped, confirmed) but an established, deliberate
|
|
124
|
-
`RadioGroup` + `FormControlLabel` convention for single-choice controls
|
|
125
|
-
(`src/messaging/PollCard.jsx:1-140`, code comment there explains why: native arrow-key nav + grouped
|
|
126
|
-
screen-reader announcement — "a bare ungrouped `Radio` per option... loses both"). Prefer
|
|
127
|
-
`RadioGroup`/`FormControlLabel` to match this repo's convention unless a segmented-button visual is
|
|
128
|
-
judged clearly better for a 4-preset picker — either is acceptable, but state which and why.
|
|
129
|
-
|
|
130
|
-
**Series toggles — `Checkbox` + `FormControlLabel` per series**, matching this repo's established
|
|
131
|
-
multi-choice pattern (`PollCard.jsx`'s multi-choice mode; also `Composer.jsx:181`,
|
|
132
|
-
`ProfileComponent.jsx:232,244`). **Accessibility requirement, verified as a real gap**: colors from
|
|
133
|
-
`getNeutralChartPalette` are assigned positionally with no name-to-color map and no shape
|
|
134
|
-
differentiation (`src/components/charts/palette.js`, full file) — so each checkbox's `label` MUST be
|
|
135
|
-
the series' text name (`FormControlLabel` gives this for free), not a bare colored swatch. Optionally
|
|
136
|
-
also render a small colored swatch next to the label (matching the series' `BarChart` color at the
|
|
137
|
-
same index) as a secondary, non-exclusive cue.
|
|
138
|
-
|
|
139
|
-
**Second y-axis — decision required by the WO, make it explicitly:** `BarChart` already supports a
|
|
140
|
-
dual-axis shape (`yAxisKey: 'secondary'` per series, paired with `yAxis={[{id:'primary'},
|
|
141
|
-
{id:'secondary'}]}`), so it is technically available — but **do not use it here**. Scope B's series
|
|
142
|
-
toggles are the WO's chosen, required fix for the shared-axis-different-units problem (jg's user
|
|
143
|
-
counts vs. presence-hours); a second y-axis is the *alternative* the WO explicitly did not choose.
|
|
144
|
-
State this decision plainly in the completion note — do not leave it to be inferred from absence.
|
|
145
|
-
|
|
146
|
-
**Empty state — all series deselected:** `ChartFrame`'s `isEmpty` prop drives its own empty-state
|
|
147
|
-
`Alert` (`:58-65`). When every series is toggled off, `TimeSeriesChart` must NOT pass an empty
|
|
148
|
-
`series` array to `BarChart` (which would likely throw or render a blank axis) — instead set
|
|
149
|
-
`isEmpty` truthy on `ChartFrame` and skip rendering `BarChart` entirely for that render, matching
|
|
150
|
-
required test 3 ("stable empty chart: no crash, no spinner").
|
|
151
|
-
|
|
152
|
-
**i18n — extend `src/i18n/chartsTranslations.ts` in place** (single `chartsTranslations` object,
|
|
153
|
-
`<ComponentName>.<CONSTANT_KEY>` convention, all four `de/fr/en/sw`, `:1-38` for the existing shape
|
|
154
|
-
to match). New keys needed: `TimeSeriesChart.RANGE_1_DAY`, `RANGE_1_WEEK`, `RANGE_1_MONTH`,
|
|
155
|
-
`RANGE_1_YEAR`, and a label for the series-toggle group (e.g. `TimeSeriesChart.SERIES_LABEL`).
|
|
156
|
-
|
|
157
|
-
**Tests — new `tests/TimeSeriesChart.test.jsx`**, matching `tests/ChartFrame.test.jsx`/
|
|
158
|
-
`tests/BarChart.test.jsx` conventions (both fully precedent): `// @vitest-environment jsdom` header,
|
|
159
|
-
vitest + `@testing-library/react`, `afterEach(cleanup)`, a minimal per-file `i18next.createInstance()`
|
|
160
|
-
+ `I18nextProvider` (not the app's real i18n config), wrapped in `ThemeProvider theme={createTheme()}`.
|
|
161
|
-
For test 1 (range emits granularity) and the series-filter tests, mock `@mui/x-charts/BarChart` itself
|
|
162
|
-
via `vi.hoisted` + `vi.mock` to inspect exact props passed through (`BarChart.test.jsx`'s own pattern,
|
|
163
|
-
`chartSpy.mock.calls[0][0]`) — do not mock ucm's own `BarChart`/`ChartFrame`, the point is testing the
|
|
164
|
-
real composition.
|
|
165
|
-
|
|
166
|
-
## NON-GOALS / DO NOT TOUCH
|
|
167
|
-
- Do not fetch data, and do not import anything app-specific.
|
|
168
|
-
- Do not change `ChartFrame`, `BarChart`, `LineChart` or the palette beyond what composing requires. If
|
|
169
|
-
`ChartFrame` lacks something, **extend it deliberately and say so** — do not work around it in the
|
|
170
|
-
preset.
|
|
171
|
-
- Do not add a charting dependency; MUI X-Charts is already the kit's basis.
|
|
172
|
-
- No persistence of the picker or toggle state — that is the host's decision.
|
|
173
|
-
|
|
174
|
-
## RISKS
|
|
175
|
-
- The toolbar slot has no consumer today, so this is its first real use. Expect to find gaps in it;
|
|
176
|
-
fixing them is in scope, working around them is not.
|
|
177
|
-
- Accessibility: the picker and checkboxes are controls, not decoration — labels, keyboard operation and
|
|
178
|
-
state must be right. Series colour alone must not be the only way to tell which toggle maps to which
|
|
179
|
-
series. `ui_reviewer` should check this specifically.
|
|
180
|
-
- Every host inherits the preset; a visible behaviour change beyond jg.
|
|
181
|
-
|
|
182
|
-
## REQUIRED TESTS TO WRITE
|
|
183
|
-
Narrow and behavioural. Do NOT run the full suite.
|
|
184
|
-
|
|
185
|
-
1. Selecting a range emits both the range **and** the mapped granularity to the callback — assert the
|
|
186
|
-
granularity, which is the half most likely to be dropped.
|
|
187
|
-
2. Toggling a series off removes it from the rendered chart and leaves the others.
|
|
188
|
-
3. Toggling **all** series off renders a stable empty chart: no crash, no spinner.
|
|
189
|
-
4. The preset renders `ChartFrame`'s empty state for empty data, exactly once.
|
|
190
|
-
|
|
191
|
-
**Non-vacuity:** test 1 must fail if only the range is emitted. Assert the emitted payload, not that a
|
|
192
|
-
callback fired.
|
|
193
|
-
|
|
194
|
-
## TEST SCOPE FOR THE GATE (orchestrator)
|
|
195
|
-
The chart component tests. Not the full suite.
|
|
196
|
-
|
|
197
|
-
## TARGET REPO
|
|
198
|
-
`C:\Users\biglmi\Documents\webapps\ui-core-micha`. Branch `main` (or `develop` if present). Publish per
|
|
199
|
-
the repo's release flow; consumer pin bumps are separate.
|
|
200
|
-
|
|
201
|
-
## MINI-HANDOVER (pastable)
|
|
202
|
-
|
|
203
|
-
> Repo: `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`, or `develop` if present).
|
|
204
|
-
> Work order: `work-orders/CHART-2.md` — read it fully, then follow the `orchestrate-codex` skill.
|
|
205
|
-
>
|
|
206
|
-
> Extends CHART-1, whose `ChartFrame` already has an unused **toolbar slot** — that is where the range
|
|
207
|
-
> picker and series toggles go. **Presentational only: the host fetches, this component takes data and
|
|
208
|
-
> callbacks.**
|
|
209
|
-
>
|
|
210
|
-
> The one thing most likely to be half-done: the range picker must emit a **granularity** alongside the
|
|
211
|
-
> window. dcm ACT-1 aggregates server-side, and a 1-year range at 4-hour buckets is ~2190 points — a
|
|
212
|
-
> picker that widens the window without coarsening the resolution reproduces the unreadable chart this
|
|
213
|
-
> WO exists to fix. Test 1 asserts the granularity for that reason.
|
|
214
|
-
>
|
|
215
|
-
> The series toggles are a real fix, not a preference: jg's two series share one y-axis with different
|
|
216
|
-
> units, which is why one of them is invisible today. If you consider a second y-axis instead, decide
|
|
217
|
-
> deliberately and say so.
|
|
218
|
-
|
|
219
|
-
## PROGRESS CONTRACT
|
|
220
|
-
Emit `PLAN: <steps>` up front, then a single-line `PROGRESS: [<n>/<total>] <action>` before every
|
|
221
|
-
relevant action and `PROGRESS: [<n>/<total>] done` on completion, spaced so no gap exceeds ~2 min,
|
|
222
|
-
stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>`.
|
package/work-orders/CHART-3.md
DELETED
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
# WORK ORDER CHART-3 (ui-core-micha) — fix TimeSeriesChart rendering nothing on async data load
|
|
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
|
-
Bug-fix WO on the landed CHART-2. Found live in jg-ferien's "Aktivität" screen (ACT-3 consumer): the
|
|
11
|
-
toolbar (range picker + series checkboxes) renders correctly, but the chart body never appears —
|
|
12
|
-
`ChartFrame`'s empty-state `Alert` shows permanently, even once real data has loaded.
|
|
13
|
-
|
|
14
|
-
## TIER
|
|
15
|
-
Tier 2 — shared-core UI consumed by every app that adopts `TimeSeriesChart`.
|
|
16
|
-
Independent `reviewer` + `ui_reviewer` mandatory.
|
|
17
|
-
|
|
18
|
-
## WHY
|
|
19
|
-
|
|
20
|
-
`TimeSeriesChart` initializes `visibleKeys` via a **lazy `useState` initializer** that reads
|
|
21
|
-
`seriesConfig` (derived from the `data` prop) only once, at first mount:
|
|
22
|
-
|
|
23
|
-
```js
|
|
24
|
-
const [visibleKeys, setVisibleKeys] = useState(
|
|
25
|
-
() => new Set(seriesConfig.map((series) => series.key)),
|
|
26
|
-
);
|
|
27
|
-
```
|
|
28
|
-
|
|
29
|
-
jg-ferien's `ActivitySection.jsx` mounts `TimeSeriesChart` with `data = { xLabels: [], series: [] }`
|
|
30
|
-
(its own initial `useState`), then fetches asynchronously in a `useEffect` and updates `data` only
|
|
31
|
-
once the API call resolves — the standard "mount empty, fill later" pattern. Because the lazy
|
|
32
|
-
initializer never re-runs on prop updates, `visibleKeys` stays a permanently empty `Set` even after
|
|
33
|
-
real series arrive. Downstream:
|
|
34
|
-
|
|
35
|
-
```js
|
|
36
|
-
const visibleSeries = seriesConfig.filter((series) => visibleKeys.has(series.key)); // always []
|
|
37
|
-
const isDataEmpty = seriesConfig.length === 0 || visibleSeries.length === 0; // always true
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
`isDataEmpty` is permanently `true`, so `ChartFrame` renders its empty-state `Alert` forever, no
|
|
41
|
-
matter how much data loads. The toolbar renders fine because the range picker and the series
|
|
42
|
-
checkboxes are driven directly off the live `seriesConfig`, not off `visibleKeys` — only the chart
|
|
43
|
-
body is gated on the stale set. This reproduces on every host that fetches asynchronously after
|
|
44
|
-
mount (the overwhelmingly common case), not just jg-ferien.
|
|
45
|
-
|
|
46
|
-
## SCOPE
|
|
47
|
-
|
|
48
|
-
**Fix `visibleKeys` to track newly-appeared series without discarding a user's manual toggle.**
|
|
49
|
-
|
|
50
|
-
Required behaviour:
|
|
51
|
-
1. When `data`/`seriesConfig` changes and introduces a series key not seen before, that key must
|
|
52
|
-
become visible by default (matches current first-mount behaviour, just not mount-only).
|
|
53
|
-
2. A series key the user has manually toggled off must **stay off** across a range change that
|
|
54
|
-
still includes that key (e.g. don't reset all toggles to "all visible" on every `data` update —
|
|
55
|
-
that would silently undo the user's own toggle, a second bug of the opposite kind).
|
|
56
|
-
3. A key that disappears from `seriesConfig` (e.g. a range change that drops a series) and later
|
|
57
|
-
reappears is treated as new for step 1 (simplest correct behaviour; do not attempt to remember
|
|
58
|
-
toggle state for absent keys unless it falls out naturally from the fix).
|
|
59
|
-
|
|
60
|
-
This is a "seen this key before, default it visible; otherwise respect the user's own toggle" sync,
|
|
61
|
-
not a full rewrite of the toggle model — `toggleSeries`, the checkbox rendering, and the empty-state
|
|
62
|
-
logic in SCOPE stay as they are; only the initialization/sync of `visibleKeys` changes.
|
|
63
|
-
|
|
64
|
-
## NON-GOALS / DO NOT TOUCH
|
|
65
|
-
- Do not change `ChartFrame`, `BarChart`, `LineChart`, or the palette.
|
|
66
|
-
- Do not change the range-picker or the range-to-granularity mapping (`RANGE_OPTIONS`).
|
|
67
|
-
- Do not add an `onSeriesToggle` callback or any other new prop/API surface — this is a bug fix
|
|
68
|
-
within the existing component contract, not a scope extension.
|
|
69
|
-
- Do not touch `chartsTranslations.ts` — this WO is unrelated to i18n (a separate, already-diagnosed
|
|
70
|
-
issue in a different repo is being fixed independently).
|
|
71
|
-
|
|
72
|
-
## RISKS
|
|
73
|
-
- The fix must not reintroduce the mount-time bug in a different form (e.g. resetting on every
|
|
74
|
-
render, or resetting on every `data` change including in-place mutations of the same series set —
|
|
75
|
-
that would silently discard the user's manual toggles on every range change, which is the
|
|
76
|
-
behaviour test 2 below exists to catch).
|
|
77
|
-
- Every host that has adopted `TimeSeriesChart` since CHART-2 shipped is affected by this fix
|
|
78
|
-
(currently only jg-ferien via ACT-3); this changes rendering behaviour for all of them, in the
|
|
79
|
-
correct direction (chart now actually renders).
|
|
80
|
-
|
|
81
|
-
## REQUIRED TESTS TO WRITE
|
|
82
|
-
Narrow and behavioural, extending `tests/TimeSeriesChart.test.jsx`. Do NOT run the full suite.
|
|
83
|
-
|
|
84
|
-
1. **Regression test for this exact bug**: mount `TimeSeriesChart` with empty `data`
|
|
85
|
-
(`{ xLabels: [], series: [] }`), then rerender with populated `data` (real `xLabels`/`series`) —
|
|
86
|
-
assert the chart body renders (not `ChartFrame`'s empty state), i.e. `isEmpty` becomes `false`
|
|
87
|
-
and `BarChart` receives the new series. This must fail against the current code and pass after
|
|
88
|
-
the fix — it is the non-vacuity check for this WO.
|
|
89
|
-
2. **Toggle persistence across a data update**: toggle one series off, then rerender with updated
|
|
90
|
-
`data` that still contains that series key (e.g. a value change, same keys) — assert that series
|
|
91
|
-
is still filtered out (the user's manual toggle was not reset by the data update).
|
|
92
|
-
3. **New series key appearing later defaults to visible**: mount with one series, rerender with a
|
|
93
|
-
second series key added — assert the new key is visible by default while any prior manual toggle
|
|
94
|
-
on the first key is preserved.
|
|
95
|
-
|
|
96
|
-
**Non-vacuity:** test 1 must fail against the current `visibleKeys` lazy-initializer code (verify
|
|
97
|
-
this before considering the fix complete) — it is reproducing the exact live bug from jg-ferien.
|
|
98
|
-
|
|
99
|
-
## CONTEXT PACKAGE — verified current state (Orchestrator, Implementation map)
|
|
100
|
-
|
|
101
|
-
Work from this package; do not explore broadly from scratch — open only the named files to verify.
|
|
102
|
-
|
|
103
|
-
**File to change: `src/components/charts/TimeSeriesChart.jsx`.**
|
|
104
|
-
|
|
105
|
-
Current state (verified, full relevant slice):
|
|
106
|
-
```js
|
|
107
|
-
const seriesConfig = data?.series || [];
|
|
108
|
-
|
|
109
|
-
const [range, setRange] = useState(defaultRange);
|
|
110
|
-
// Series identity (keys) is assumed stable for a given chart instance — the
|
|
111
|
-
// toggle set is initialized once from the first data the chart receives.
|
|
112
|
-
const [visibleKeys, setVisibleKeys] = useState(
|
|
113
|
-
() => new Set(seriesConfig.map((series) => series.key)),
|
|
114
|
-
);
|
|
115
|
-
```
|
|
116
|
-
(`TimeSeriesChart.jsx:52-59`) — the comment above `visibleKeys` states the now-disproven assumption
|
|
117
|
-
("series identity is stable for a given chart instance") that this WO corrects; update or remove it
|
|
118
|
-
to match the new behaviour.
|
|
119
|
-
|
|
120
|
-
`toggleSeries` (`:68-75`), `visibleSeries`/`visiblePalette`/`isDataEmpty` derivation (`:77-84`), and
|
|
121
|
-
the checkbox rendering (`:103-123`) are all downstream of `visibleKeys` and should not need changes
|
|
122
|
-
— only how `visibleKeys` is initialized/kept in sync with `seriesConfig` changes.
|
|
123
|
-
|
|
124
|
-
**Suggested shape (not prescriptive — implement whatever satisfies SCOPE correctly):** replace the
|
|
125
|
-
lazy `useState` with a `useEffect` keyed on the set of series keys in `seriesConfig`, that adds any
|
|
126
|
-
newly-seen key to `visibleKeys` (defaulting it visible) without touching keys already present in the
|
|
127
|
-
set — e.g. track previously-seen keys in a ref to detect "new" vs "toggled off", since a key
|
|
128
|
-
present in both old and new `seriesConfig` but absent from `visibleKeys` must stay absent (it was a
|
|
129
|
-
deliberate user toggle-off, not a fresh key). Keep `visibleKeys`'s existing `Set`-of-keys shape,
|
|
130
|
-
`toggleSeries`'s update pattern, and the checkbox/empty-state code untouched.
|
|
131
|
-
|
|
132
|
-
**Test file to extend: `tests/TimeSeriesChart.test.jsx`** — matches `tests/ChartFrame.test.jsx`/
|
|
133
|
-
`tests/BarChart.test.jsx` conventions: `// @vitest-environment jsdom` header, vitest +
|
|
134
|
-
`@testing-library/react`, `afterEach(cleanup)`, a minimal per-file `i18next.createInstance()` +
|
|
135
|
-
`I18nextProvider`, wrapped in `ThemeProvider theme={createTheme()}`. Use `rerender()` from
|
|
136
|
-
`@testing-library/react`'s `render()` return value to simulate the host updating `data` after mount
|
|
137
|
-
(this is the exact scenario CHART-2's own tests never covered — they only mounted once with
|
|
138
|
-
synchronous populated data).
|
|
139
|
-
|
|
140
|
-
## TARGET REPO
|
|
141
|
-
`C:\Users\biglmi\Documents\webapps\ui-core-micha`. Branch `main`. Publish per the repo's release
|
|
142
|
-
flow (patch bump — bug fix, no interface change); consumer pin bumps are separate, out of scope.
|
|
143
|
-
|
|
144
|
-
## TEST SCOPE FOR THE GATE (orchestrator)
|
|
145
|
-
`tests/TimeSeriesChart.test.jsx` only. Not the full suite.
|
|
146
|
-
|
|
147
|
-
## MINI-HANDOVER (pastable)
|
|
148
|
-
|
|
149
|
-
> Repo: `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`).
|
|
150
|
-
> Work order: `work-orders/CHART-3.md` — read it fully, then follow the `orchestrate-codex` skill.
|
|
151
|
-
>
|
|
152
|
-
> Bug fix on CHART-2's `TimeSeriesChart`: `visibleKeys` is initialized once via a lazy `useState`
|
|
153
|
-
> from whatever `data` is at first mount, so any host that fetches asynchronously after mount (the
|
|
154
|
-
> normal case) ends up with a permanently-empty `visibleKeys` and the chart body never renders —
|
|
155
|
-
> `ChartFrame`'s empty state shows forever even once real data arrives. Fix the sync so newly-seen
|
|
156
|
-
> series keys default to visible while a user's manual toggle-off on an already-seen key survives a
|
|
157
|
-
> data update. Regression test 1 is the non-vacuity check — verify it fails against current code
|
|
158
|
-
> first.
|
|
159
|
-
|
|
160
|
-
## PROGRESS CONTRACT
|
|
161
|
-
Emit `PLAN: <steps>` up front, then a single-line `PROGRESS: [<n>/<total>] <action>` before every
|
|
162
|
-
relevant action and `PROGRESS: [<n>/<total>] done` on completion, spaced so no gap exceeds ~2 min,
|
|
163
|
-
stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>`.
|
package/work-orders/CHART-4.md
DELETED
|
@@ -1,203 +0,0 @@
|
|
|
1
|
-
# WORK ORDER CHART-4 (ui-core-micha) — TimeSeriesChart renders no chart body (zero height)
|
|
2
|
-
|
|
3
|
-
**EXECUTION DIRECTIVE.** If you are the implementer reading this as your own spec, this section is not
|
|
4
|
-
addressed to you — it tells the Orchestrator how to invoke you; you ARE that invocation, do not shell
|
|
5
|
-
out to `codex exec`. Orchestrator: implement through `codex exec` in the background, invoked **directly
|
|
6
|
-
via Bash** (never the `debugger`/`*_coder` Agent wrappers) with **both** flags `--skip-git-repo-check`
|
|
7
|
-
and `--dangerously-bypass-approvals-and-sandbox`, prompt passed as a positional argument from this
|
|
8
|
-
file. Fall back to direct Claude implementation only on Codex quota / rate-limit / non-zero exit.
|
|
9
|
-
**Known at WO authoring time: the Codex workspace is out of credits for this session — the fallback
|
|
10
|
-
applies immediately, do not spend time retrying `codex exec` first.**
|
|
11
|
-
|
|
12
|
-
Bug-fix WO on CHART-2/CHART-3. Found live in jg-ferien's "Aktivität" screen (ACT-3/ACT-5 consumer)
|
|
13
|
-
immediately after CHART-3 shipped and jg's pin was bumped: the toolbar, series checkboxes, and MUI
|
|
14
|
-
X-Charts **legend** now all render correctly (proving CHART-3's fix works and real data is present),
|
|
15
|
-
but the chart canvas itself — bars and axes — is entirely absent. The card ends right after the
|
|
16
|
-
legend row with visible empty space beneath it.
|
|
17
|
-
|
|
18
|
-
## TIER
|
|
19
|
-
Tier 2 — shared-core UI consumed by every app that adopts `TimeSeriesChart`.
|
|
20
|
-
Independent `reviewer` + `ui_reviewer` mandatory.
|
|
21
|
-
|
|
22
|
-
## WHY
|
|
23
|
-
|
|
24
|
-
`TimeSeriesChart` composes `ChartFrame` + `BarChart` but never supplies either with a height:
|
|
25
|
-
|
|
26
|
-
```jsx
|
|
27
|
-
<ChartFrame title={title} subtitle={subtitle} toolbar={toolbar} loading={loading} error={error} isEmpty={isDataEmpty}>
|
|
28
|
-
{!isDataEmpty && (
|
|
29
|
-
<BarChart xAxisLabel={xAxisLabel} yAxisLabel={yAxisLabel} xAxis={[{ data: data?.xLabels || [] }]}
|
|
30
|
-
series={visibleSeries.map(...)} palette={visiblePalette} />
|
|
31
|
-
)}
|
|
32
|
-
</ChartFrame>
|
|
33
|
-
```
|
|
34
|
-
|
|
35
|
-
Neither `minHeight`/`aspect` (ChartFrame's own sizing props) nor `minHeight`/`aspect`/a raw MUI
|
|
36
|
-
`height` (BarChart's) are passed. `ChartFrame`'s inner content `Box` has `display: flex, alignItems:
|
|
37
|
-
center, justifyContent: center` with no defined height — with `alignItems: center` (not `stretch`),
|
|
38
|
-
a flex child gets its own intrinsic height, not the parent's. `BarChart`'s own wrapping `Box` (`sx:
|
|
39
|
-
{width:'100%', minHeight, aspectRatio}`) therefore also has no height when neither prop is supplied.
|
|
40
|
-
MUI X-Charts' internal responsive container measures its actual parent height via `ResizeObserver` to
|
|
41
|
-
size the SVG — with a zero-height parent, the chart canvas (bars, axes) renders at zero size. The
|
|
42
|
-
**legend** is a separate MUI X-Charts sub-component sized by its own content (text + swatches), so it
|
|
43
|
-
renders regardless of container height — which is exactly why the legend was the only visible sign
|
|
44
|
-
of a mounted chart in the live screenshot.
|
|
45
|
-
|
|
46
|
-
This gap was invisible until now because CHART-3's own bug (`visibleKeys` never populating) kept
|
|
47
|
-
`isDataEmpty` permanently `true`, so `BarChart` never actually mounted in any live deployment before
|
|
48
|
-
today. It also went uncaught by CHART-2's and CHART-3's own tests: both `tests/BarChart.test.jsx` and
|
|
49
|
-
`tests/TimeSeriesChart.test.jsx` mock `@mui/x-charts/BarChart` itself (`vi.mock('@mui/x-charts/BarChart', ...)`
|
|
50
|
-
per CHART-2's own required-tests convention), so no test in this repo has ever mounted the *real* MUI
|
|
51
|
-
chart and observed its rendered size. The working reference is `dev/entries.jsx`'s `BarChartEntry`
|
|
52
|
-
(DX-1 harness), which explicitly sets `minHeight={360}` on `ChartFrame` and `height={320}` directly
|
|
53
|
-
on `BarChart` — i.e. every other real consumer of these primitives in this repo already knows it must
|
|
54
|
-
supply a height; `TimeSeriesChart`, as a preset built on top, was supposed to supply this itself
|
|
55
|
-
(hosts don't see `ChartFrame`/`BarChart` directly through the preset) and doesn't.
|
|
56
|
-
|
|
57
|
-
## SCOPE
|
|
58
|
-
|
|
59
|
-
**Give `TimeSeriesChart` a sensible built-in height for the chart it composes**, matching the
|
|
60
|
-
DX-1-proven working pattern:
|
|
61
|
-
1. Pass `minHeight` to `ChartFrame` (sizes the loading/error/empty states too, not just the chart).
|
|
62
|
-
2. Pass a height down to `BarChart` so the actual MUI chart canvas gets a real, non-zero pixel size —
|
|
63
|
-
either `BarChart`'s own `minHeight`/`aspect` wrapper props, or a raw `height` forwarded via
|
|
64
|
-
`BarChart`'s `...chartProps` pass-through to `MuiBarChart` (the mechanism `dev/entries.jsx` uses
|
|
65
|
-
directly against `BarChart`, confirmed working there). Pick whichever actually renders a non-zero
|
|
66
|
-
chart canvas when verified (see REQUIRED TESTS) — do not assume `aspectRatio` CSS alone reliably
|
|
67
|
-
drives MUI X-Charts' `ResizeObserver` sizing without checking; the raw `height` prop is the
|
|
68
|
-
confirmed-working mechanism in this repo's own reference usage and is the safer default if there
|
|
69
|
-
is any doubt.
|
|
70
|
-
3. Pick one fixed value (e.g. `320`/`360`, matching `dev/entries.jsx`'s own numbers) as a preset
|
|
71
|
-
default — this is a preset, not a raw primitive; the host does not choose chart height, matching
|
|
72
|
-
`TimeSeriesChart`'s existing "no new props" presentational contract. Do not add a new prop for
|
|
73
|
-
this unless a reviewer specifically asks for one.
|
|
74
|
-
|
|
75
|
-
**This WO's real fix is the test gap, not just the pixels.** The reason this shipped broken twice is
|
|
76
|
-
that every test in this file mocks the real MUI chart component. Required test 1 below must exercise
|
|
77
|
-
the **unmocked** `@mui/x-charts/BarChart` and assert a real rendered size — a mocked-chart test would
|
|
78
|
-
be exactly the kind of vacuous coverage that let this ship.
|
|
79
|
-
|
|
80
|
-
## NON-GOALS / DO NOT TOUCH
|
|
81
|
-
- Do not change the range picker, series toggles, `chartsTranslations`, or the CHART-3 `visibleKeys`
|
|
82
|
-
sync logic — this WO is scoped to sizing only.
|
|
83
|
-
- Do not change `ChartFrame`'s or `BarChart`'s own prop contracts (`minHeight`/`aspect` already exist
|
|
84
|
-
on both) — only how `TimeSeriesChart` calls them.
|
|
85
|
-
- Do not add a new prop to `TimeSeriesChart`'s public API for this — see SCOPE point 3.
|
|
86
|
-
|
|
87
|
-
## RISKS
|
|
88
|
-
- Every host that has adopted `TimeSeriesChart` is affected (currently jg-ferien via ACT-3/ACT-5) —
|
|
89
|
-
this changes rendering behaviour for all of them, in the correct direction (chart canvas now
|
|
90
|
-
actually visible).
|
|
91
|
-
- Getting this wrong a second time (e.g. an `aspectRatio`-only fix that still doesn't reliably drive
|
|
92
|
-
MUI X-Charts' internal measurement) ships a third silent failure in the same component. The
|
|
93
|
-
required unmocked-render test exists specifically to catch that before it reaches a live app again.
|
|
94
|
-
|
|
95
|
-
## REQUIRED TESTS TO WRITE
|
|
96
|
-
Extend `tests/TimeSeriesChart.test.jsx`. Do NOT run the full suite.
|
|
97
|
-
|
|
98
|
-
1. **The real bug's mechanism, not a jsdom layout measurement.** An initial attempt at this WO wrote
|
|
99
|
-
an *unmocked* test (real `@mui/x-charts/BarChart`, no `vi.mock`) asserting the rendered chart
|
|
100
|
-
surface's `viewBox` height was non-zero — verified, in practice, to be **vacuous**: it stayed green
|
|
101
|
-
even with the pre-fix code (no `height` prop anywhere), because jsdom's `ResizeObserver`/layout
|
|
102
|
-
handling does not reproduce the real-browser zero-height-parent behaviour this bug depends on. Do
|
|
103
|
-
not repeat that approach. Instead, keep the existing `chartSpy` mock convention (`vi.hoisted` +
|
|
104
|
-
`vi.mock('@mui/x-charts/BarChart', ...)`, already at `tests/TimeSeriesChart.test.jsx:9-10`) and
|
|
105
|
-
assert directly on the props the real `MuiBarChart` receives: `chartSpy.mock.calls.at(-1)[0].height`
|
|
106
|
-
must be a real, non-zero number. This is what actually distinguishes fixed from broken — confirmed
|
|
107
|
-
by reverting the fix and re-running: the prop assertion fails pre-fix (`props.height` is
|
|
108
|
-
`undefined`), the unmocked viewBox assertion does not.
|
|
109
|
-
2. **Non-vacuity**: this test must fail against the current (pre-fix) code — verify before considering
|
|
110
|
-
the fix complete (see note above — already verified once for the prop-assertion approach).
|
|
111
|
-
3. Existing mocked-`BarChart` tests (range/toggle/empty-state behaviour) stay as they are.
|
|
112
|
-
|
|
113
|
-
## CONTEXT PACKAGE — verified current state (Orchestrator, Implementation map)
|
|
114
|
-
|
|
115
|
-
Work from this package; do not explore broadly from scratch — open only the named files to verify.
|
|
116
|
-
|
|
117
|
-
**File to change: `src/components/charts/TimeSeriesChart.jsx`.**
|
|
118
|
-
|
|
119
|
-
Current return statement (verified, full slice, `:150-169`):
|
|
120
|
-
```jsx
|
|
121
|
-
return (
|
|
122
|
-
<ChartFrame
|
|
123
|
-
title={title}
|
|
124
|
-
subtitle={subtitle}
|
|
125
|
-
toolbar={toolbar}
|
|
126
|
-
loading={loading}
|
|
127
|
-
error={error}
|
|
128
|
-
isEmpty={isDataEmpty}
|
|
129
|
-
>
|
|
130
|
-
{!isDataEmpty && (
|
|
131
|
-
<BarChart
|
|
132
|
-
xAxisLabel={xAxisLabel}
|
|
133
|
-
yAxisLabel={yAxisLabel}
|
|
134
|
-
xAxis={[{ data: data?.xLabels || [] }]}
|
|
135
|
-
series={visibleSeries.map((series) => ({ data: series.data, label: series.label }))}
|
|
136
|
-
palette={visiblePalette}
|
|
137
|
-
/>
|
|
138
|
-
)}
|
|
139
|
-
</ChartFrame>
|
|
140
|
-
);
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
**Reference (working) pattern — `dev/entries.jsx:35-39`:**
|
|
144
|
-
```jsx
|
|
145
|
-
function BarChartEntry() {
|
|
146
|
-
return (
|
|
147
|
-
<ChartFrame title="Monthly cases" subtitle="Standalone BarChart entry" minHeight={360}>
|
|
148
|
-
<BarChart {...barChartFixture} xAxisLabel="Month" yAxisLabel="Cases" height={320} />
|
|
149
|
-
</ChartFrame>
|
|
150
|
-
);
|
|
151
|
-
}
|
|
152
|
-
```
|
|
153
|
-
Note `height={320}` on `BarChart` here is NOT `BarChart`'s own `minHeight`/`aspect` wrapper prop — it
|
|
154
|
-
lands in `BarChart`'s `...chartProps` rest spread (`BarChart.jsx:24,34`) and is forwarded straight to
|
|
155
|
-
`MuiBarChart`'s own native `height` prop, which MUI X-Charts uses as a fixed pixel height instead of
|
|
156
|
-
measuring the parent via `ResizeObserver`. This is the confirmed-working mechanism in this repo.
|
|
157
|
-
|
|
158
|
-
**`ChartFrame.jsx:86-99`** — the content `Box`: `sx={{ width:'100%', minHeight, aspectRatio: aspect,
|
|
159
|
-
display:'flex', alignItems:'center', justifyContent:'center' }}`. `alignItems:'center'` means a flex
|
|
160
|
-
child (here, `BarChart`'s own `Box`) is NOT stretched to fill this Box's height — it keeps its own
|
|
161
|
-
intrinsic height. Passing `minHeight` to `ChartFrame` sizes this outer Box correctly for the
|
|
162
|
-
loading/error/empty `Alert`/`CircularProgress` states (which have no fixed height of their own and
|
|
163
|
-
DO benefit from the flex-centered parent height), but does **not**, by itself, give `BarChart`'s
|
|
164
|
-
child `Box` any height — that must come from `BarChart` itself (its own `minHeight`/`aspect`, or the
|
|
165
|
-
raw `height` chartProp per the reference pattern above).
|
|
166
|
-
|
|
167
|
-
**`BarChart.jsx:15-44`** — full file, already shown above in this WO's WHY section — `minHeight`/
|
|
168
|
-
`aspect` are explicit named props (`:22-23`) applied to `BarChart`'s own wrapping `Box` (`:32`);
|
|
169
|
-
anything else lands in `...chartProps` (`:24`) and is spread onto `MuiBarChart` directly (`:34`),
|
|
170
|
-
which is how a raw `height` reaches the underlying MUI component.
|
|
171
|
-
|
|
172
|
-
**Test file: `tests/TimeSeriesChart.test.jsx`** — already mocks `@mui/x-charts/BarChart` via
|
|
173
|
-
`vi.hoisted` + `vi.mock` (`:9-10`) and every existing test reads `chartSpy.mock.calls.at(-1)[0]` to
|
|
174
|
-
assert exact props (e.g. the `series`/`colors` assertions at `:87-89,94-99`). Add the new test in the
|
|
175
|
-
same style, asserting `props.height` — see REQUIRED TESTS above for why an unmocked render test does
|
|
176
|
-
NOT work here.
|
|
177
|
-
|
|
178
|
-
## TARGET REPO
|
|
179
|
-
`C:\Users\biglmi\Documents\webapps\ui-core-micha`. Branch `main`. Publish per the repo's release
|
|
180
|
-
flow (patch bump — bug fix, no interface change).
|
|
181
|
-
|
|
182
|
-
## TEST SCOPE FOR THE GATE (orchestrator)
|
|
183
|
-
`tests/TimeSeriesChart.test.jsx`. Not the full suite.
|
|
184
|
-
|
|
185
|
-
## MINI-HANDOVER (pastable)
|
|
186
|
-
|
|
187
|
-
> Repo: `C:\Users\biglmi\Documents\webapps\ui-core-micha` (branch `main`).
|
|
188
|
-
> Work order: `work-orders/CHART-4.md` — read it fully, then follow the `orchestrate-codex` skill.
|
|
189
|
-
> **Codex workspace is out of credits this session — go straight to the direct-Claude fallback, do
|
|
190
|
-
> not attempt `codex exec` first.**
|
|
191
|
-
>
|
|
192
|
-
> Second bug in `TimeSeriesChart` (after CHART-3): the chart legend renders but the actual bars/axes
|
|
193
|
-
> never appear because neither `ChartFrame` nor `BarChart` ever receive a height — MUI X-Charts'
|
|
194
|
-
> responsive container measures a zero-height parent and draws nothing. `dev/entries.jsx`'s
|
|
195
|
-
> `BarChartEntry` is the proof this is fixable: `minHeight={360}` on `ChartFrame` + `height={320}`
|
|
196
|
-
> forwarded straight to `BarChart` (MUI's own native height prop, not the wrapper's `minHeight`/
|
|
197
|
-
> `aspect`). The required regression test must NOT mock `@mui/x-charts/BarChart` — every existing test
|
|
198
|
-
> in this component mocks it, which is exactly how two sizing/rendering bugs shipped undetected.
|
|
199
|
-
|
|
200
|
-
## PROGRESS CONTRACT
|
|
201
|
-
Emit `PLAN: <steps>` up front, then a single-line `PROGRESS: [<n>/<total>] <action>` before every
|
|
202
|
-
relevant action and `PROGRESS: [<n>/<total>] done` on completion, spaced so no gap exceeds ~2 min,
|
|
203
|
-
stdout unbuffered, and exactly one final `RESULT: DONE|BLOCKED <reason>`.
|