-
Notifications
You must be signed in to change notification settings - Fork 48
Share GlobalHealthBar via Module Federation #4875
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
828adbb
7bc792d
3fc94ab
c9a6997
5cb8a0e
a3c38a2
fb3da8a
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,85 @@ | ||
| import { IconHelp, Loader, SmallerText, Stack, Text } from '@scality/core-ui'; | ||
| import { Alert, Box, GlobalHealthBar as GlobalHealthBarRecharts, useMetricsTimeSpan } from '@scality/core-ui/dist/next'; | ||
| import { useIntl } from 'react-intl'; | ||
| import { useQuery } from 'react-query'; | ||
| import styled from 'styled-components'; | ||
| import { highestAlertToStatus, useAlertLibrary, useHighestSeverityAlerts } from '../containers/AlertProvider'; | ||
| import { useStartingTimeStamp } from '../containers/StartTimeProvider'; | ||
| import { getClusterAlertSegmentQuery } from '../services/platformlibrary/metrics'; | ||
| import CircleStatus from './CircleStatus'; | ||
|
|
||
| const HealthBarContainer = styled.div` | ||
| flex-direction: column; | ||
| margin: 0 auto; | ||
| `; | ||
|
|
||
| const PlatformGlobalHealthBar = ({ title = 'Global Health' }: { title?: string }) => { | ||
| const intl = useIntl(); | ||
| const { startingTimeISO, currentTimeISO } = useStartingTimeStamp(); | ||
| const alertsLibrary = useAlertLibrary(); | ||
| const { duration } = useMetricsTimeSpan(); | ||
| const { data: alerts, status: historyAlertStatus } = useQuery({ | ||
| ...getClusterAlertSegmentQuery(duration), | ||
| keepPreviousData: true, | ||
| }); | ||
| const platformHighestSeverityAlert = useHighestSeverityAlerts(alertsLibrary.getPlatformAlertSelectors()); | ||
| const platformStatus = highestAlertToStatus(platformHighestSeverityAlert); | ||
|
|
||
| return ( | ||
| <HealthBarContainer> | ||
| <Stack | ||
| style={{ | ||
| display: 'flex', | ||
| alignItems: 'center', | ||
| }} | ||
| gap="r8" | ||
| > | ||
| <CircleStatus status={platformStatus} /> | ||
| <Text variant="Large" isEmphazed> | ||
| {title} | ||
| </Text> | ||
| <IconHelp | ||
| placement="bottom" | ||
| tooltipMessage={ | ||
| <Stack direction="vertical" gap="r4"> | ||
| {intl | ||
| .formatMessage({ | ||
| id: 'global_health_explanation', | ||
| }) | ||
| .split('\n') | ||
| .map((line, key) => ( | ||
| <SmallerText key={`globalheathexplanation-${key}`}>{line}</SmallerText> | ||
| ))} | ||
| </Stack> | ||
| } | ||
| /> | ||
| </Stack> | ||
|
|
||
| {historyAlertStatus === 'loading' ? ( | ||
| <Box ml={8} height={50}> | ||
| <Loader size={'larger'} /> | ||
| </Box> | ||
| ) : ( | ||
| <GlobalHealthBarRecharts | ||
| id={'platform_globalhealth'} | ||
| alerts={ | ||
| historyAlertStatus === 'error' | ||
| ? ([ | ||
| { | ||
| startsAt: startingTimeISO, | ||
| endsAt: currentTimeISO, | ||
| severity: 'unavailable', | ||
| description: 'Failed to load alert history for the selected period', | ||
| }, | ||
| ] as Alert[]) | ||
| : alerts || [] | ||
| } | ||
| start={new Date(startingTimeISO)} | ||
| end={new Date(currentTimeISO)} | ||
| /> | ||
| )} | ||
| </HealthBarContainer> | ||
| ); | ||
| }; | ||
|
|
||
| export default PlatformGlobalHealthBar; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| import { MetricsTimeSpanContext } from '@scality/core-ui/dist/components/charts/MetricsTimeSpanProvider'; | ||
| import { useShellHooks } from '@scality/module-federation'; | ||
| import { useLayoutEffect } from 'react'; | ||
| import FederatedIntlProvider from '../containers/IntlProvider'; | ||
| import StartTimeProvider from '../containers/StartTimeProvider'; | ||
| import { initialize as initializePrometheus, setHeaders } from '../services/prometheus/api'; | ||
| import PlatformGlobalHealthBar from './PlatformGlobalHealthBar'; | ||
|
|
||
| // 7-day defaults — same constants as core-ui's SAMPLE_DURATION/FREQUENCY_LAST_SEVEN_DAYS | ||
| const DEFAULT_DURATION_SECONDS = 7 * 24 * 60 * 60; | ||
| const DEFAULT_FREQUENCY_SECONDS = 60 * 60; | ||
|
|
||
| type Props = { | ||
| prometheusUrl: string; | ||
| title?: string; | ||
| durationSeconds?: number; | ||
| frequencySeconds?: number; | ||
| }; | ||
|
|
||
| export default function PlatformGlobalHealthBarFederated({ | ||
| prometheusUrl, | ||
| title, | ||
| durationSeconds = DEFAULT_DURATION_SECONDS, | ||
| frequencySeconds = DEFAULT_FREQUENCY_SECONDS, | ||
| }: Props) { | ||
| const { useAuth } = useShellHooks(); | ||
| const { userData } = useAuth(); | ||
| const token = userData?.token; | ||
|
|
||
| useLayoutEffect(() => { | ||
| if (token) { | ||
| initializePrometheus(prometheusUrl); | ||
| setHeaders({ Authorization: `Bearer ${token}` }); | ||
| } | ||
| }, [prometheusUrl, token]); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Race condition:
Comment on lines
+36
to
+41
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. initializePrometheus is an alias for initialize from prometheus api: The component will be used in artesca, if the prometheus is not initialized the query will throw an error |
||
|
|
||
| if (!token) return null; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Race condition: |
||
|
|
||
| const timeSpan = { | ||
| query: '', | ||
| label: '', | ||
| duration: durationSeconds, | ||
| interval: frequencySeconds, | ||
| frequency: frequencySeconds, // StartTimeProvider reads this deprecated field | ||
| }; | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| return ( | ||
| <MetricsTimeSpanContext.Provider value={timeSpan}> | ||
| <StartTimeProvider> | ||
| <FederatedIntlProvider> | ||
| <PlatformGlobalHealthBar title={title} /> | ||
|
JeanMarcMilletScality marked this conversation as resolved.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. PlatformGlobalHealthBar calls useHighestSeverityAlerts() and useAlertLibrary(), which both rely on useShellAlerts(). The other federated component (AlertNavbarUpdaterComponent) explicitly wraps its children with AlertProvider to ensure alert hooks work. This component omits it — is the host app guaranteed to have AlertsProvider in its tree above the mount point for this federated component? If not, these hooks may fail at runtime.
JeanMarcMilletScality marked this conversation as resolved.
|
||
| </FederatedIntlProvider> | ||
| </StartTimeProvider> | ||
| </MetricsTimeSpanContext.Provider> | ||
| ); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The original HealthBarContainer had width: 90%; margin: 0 auto; which is now removed. This changes the dashboard layout — the health bar will render at full parent width instead of centered at 90%. Intentional?
— Claude Code