Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export const HIGH_AVAILABILITY_BADGE_HEALTH = {
healthy: 'Healthy',
'at-risk': 'At Risk',
down: 'Down',
updating: 'Updating',
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { Theme } from '@mui/material/styles';
import { PEAK_DARK_THEME, PEAK_LIGHT_THEME } from '@pmm/shared';

export const getStyles = (theme: Theme) => ({
healthy: {
color: theme.palette.text.primary,
borderColor: theme.palette.text.primary,
},
'at-risk': {
color:
theme.palette.mode === 'light'
? PEAK_LIGHT_THEME.brand.sunrise[700]
: PEAK_DARK_THEME.extra.yellow[100],
borderColor:
theme.palette.mode === 'light'
? PEAK_LIGHT_THEME.brand.sunrise[700]
: PEAK_DARK_THEME.extra.yellow[100],
},
down: {
color:
theme.palette.mode === 'light'
? PEAK_DARK_THEME.error.dark
: theme.palette.error.contrastText,
backgroundColor:
theme.palette.mode === 'light'
? PEAK_LIGHT_THEME.extra.red[50]
: PEAK_DARK_THEME.error.dark,
transition: 'none',
},
updating: {
color:
theme.palette.mode === 'light'
? PEAK_LIGHT_THEME.brand.sky[600]
: PEAK_DARK_THEME.brand.sky[400],
borderColor:
theme.palette.mode === 'light'
? PEAK_LIGHT_THEME.brand.sky[600]
: PEAK_DARK_THEME.brand.sky[400],
},
});
30 changes: 30 additions & 0 deletions ui/apps/pmm/src/components/ha-badge/HighAvailabilityBadge.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import Chip, { ChipProps } from '@mui/material/Chip';
import { FC } from 'react';
import { HIGH_AVAILABILITY_BADGE_HEALTH } from './HighAvailabilityBadge.constants';
import { useTheme } from '@mui/material/styles';
import { getStyles } from './HighAvailabilityBadge.styles';
import { HighAvailabilityHealth } from 'types/high-availability.types';
import Stack from '@mui/material/Stack';

interface Props extends ChipProps {
health: HighAvailabilityHealth;
}

const HighAvailabilityBadge: FC<Props> = ({ health, ...props }) => {
const theme = useTheme();
const styles = getStyles(theme);

return (
<Stack flex={8} alignItems="flex-start">
<Chip
color="warning"
variant={health !== 'down' ? 'outlined' : 'filled'}
label={HIGH_AVAILABILITY_BADGE_HEALTH[health]}
sx={styles[health]}
{...props}
/>
</Stack>
);
};

export default HighAvailabilityBadge;
1 change: 1 addition & 0 deletions ui/apps/pmm/src/components/ha-badge/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as HighAvailabilityBadge } from './HighAvailabilityBadge';
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import { Theme } from '@mui/material';
import { PEAK_DARK_THEME, PEAK_LIGHT_THEME } from '@pmm/shared';

export const getStyles = ({ palette: { mode, background } }: Theme) => ({
icon: {
width: 20,
height: 20,

'.background': {
fill: background.default,
},
'.status-at-risk': {
fill:
mode === 'light'
? PEAK_LIGHT_THEME.brand.sunrise[700]
: PEAK_DARK_THEME.extra.yellow[100],
},
'.status-down': {
fill:
mode === 'light'
? PEAK_LIGHT_THEME.extra.red[500]
: PEAK_DARK_THEME.extra.red[200],
},
'.status-updating': {
fill:
mode === 'light'
? PEAK_LIGHT_THEME.brand.sky[600]
: PEAK_DARK_THEME.brand.sky[400],
},
},
});
35 changes: 35 additions & 0 deletions ui/apps/pmm/src/components/ha-icon/HighAvailabilityIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { useTheme } from '@mui/material';
import Box from '@mui/material/Box';
import { Icon } from 'components/icon';
import { IconName } from 'components/icon/Icon.types';
import { FC } from 'react';
import { HighAvailabilityHealth } from 'types/high-availability.types';
import { getStyles } from './HighAvailabilityIcon.styles';

interface Props {
health: HighAvailabilityHealth;
}

const HighAvailabilityIcon: FC<Props> = ({ health }) => {
const theme = useTheme();
const styles = getStyles(theme);

return (
<Box sx={{ position: 'relative' }}>
<Icon name="cluster" />
{health !== 'healthy' && (
<Box sx={{ position: 'absolute', top: -4, right: -7 }}>
<Icon sx={styles.icon} name={ICON_MAP[health]} />
</Box>
)}
</Box>
);
};

const ICON_MAP: Record<Exclude<HighAvailabilityHealth, 'healthy'>, IconName> = {
'at-risk': 'status-at-risk',
down: 'status-down',
updating: 'status-updating',
};

export default HighAvailabilityIcon;
1 change: 1 addition & 0 deletions ui/apps/pmm/src/components/ha-icon/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { default as HighAvailabilityIcon } from './HighAvailabilityIcon';
5 changes: 5 additions & 0 deletions ui/apps/pmm/src/components/icon/Icon.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,11 @@ export const DYNAMIC_ICON_IMPORT_MAP = {
'my-organization': () => import('icons/my-organization.svg?react'),
memory: () => import('icons/memory.svg?react'),
network: () => import('icons/network.svg?react'),
cluster: () => import('icons/cluster.svg?react'),
'status-at-risk': () => import('icons/status-at-risk.svg?react'),
'status-down': () => import('icons/status-down.svg?react'),
'status-updating': () => import('icons/status-updating.svg?react'),
'arrow-link': () => import('icons/arrow-link.svg?react'),
};

export const VIEWBOX_MAP: Partial<
Expand Down
14 changes: 5 additions & 9 deletions ui/apps/pmm/src/components/sidebar/nav-item/NavItem.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ import IconButton from '@mui/material/IconButton';
import NavItemTooltip from './nav-item-tooltip/NavItemTooltip';
import { DRAWER_WIDTH } from '../drawer/Drawer.constants';
import NavItemDot from './nav-item-dot/NavItemDot';
import Chip from '@mui/material/Chip';
import NavItemBadge from './nav-item-badge/NavItemBadge';
import Box from '@mui/material/Box';

const NavItem: FC<NavItemProps> = ({
Expand Down Expand Up @@ -112,6 +112,9 @@ const NavItem: FC<NavItemProps> = ({
className="navitem-primary-text"
sx={styles.text}
/>
{item.badge && item.badgeAlwaysVisible && drawerOpen && (
<NavItemBadge badge={item.badge} />
)}
</ListItemButton>
{drawerOpen && (
<IconButton
Expand Down Expand Up @@ -203,14 +206,7 @@ const NavItem: FC<NavItemProps> = ({
className="navitem-primary-text"
sx={styles.text}
/>
{item.badge && (
<Chip
size="small"
color="warning"
variant="outlined"
{...item.badge}
/>
)}
{item.badge && <NavItemBadge badge={item.badge} />}
</ListItemButton>
</ListItem>
</NavItemTooltip>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export const getLinkProps = (item: NavItem, url?: string) => {
};

export const shouldShowBadge = (item: NavItem, expanded: boolean): boolean => {
if (item.badge && !expanded) {
if (item.badge && !expanded && !item.badgeAlwaysVisible) {
return true;
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import Chip from '@mui/material/Chip';
import { FC, isValidElement } from 'react';
import { NavItem } from 'types/navigation.types';

interface Props {
badge: NavItem['badge'];
}

const NavItemBadge: FC<Props> = ({ badge: Badge }) => {
if (isValidElement(Badge)) {
return Badge;
}

if (typeof Badge === 'object' && Badge !== null) {
return <Chip size="small" color="warning" variant="outlined" {...Badge} />;
}

return null;
};

export default NavItemBadge;
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,16 @@ interface Props {
icon: NonNullable<NavItem['icon']>;
}

const NavItemIcon: FC<Props> = ({ icon: NavIcon }) =>
typeof NavIcon === 'string' ? <Icon name={NavIcon} /> : <NavIcon />;
const NavItemIcon: FC<Props> = ({ icon: NavIcon }) => {
if (typeof NavIcon === 'string') {
return <Icon name={NavIcon} />;
}

if (typeof NavIcon === 'function') {
return <NavIcon />;
}

return NavIcon;
};

export default NavItemIcon;
29 changes: 29 additions & 0 deletions ui/apps/pmm/src/contexts/navigation/navigation.constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -789,3 +789,32 @@ export const NAV_OTHER_DASHBOARDS_TEMPLATE: Partial<NavItem> = {
icon: 'search',
text: 'Other dashboards',
};

/*
* High Availability
*/
export const NAV_HIGH_AVAILABILITY: NavItem = {
id: 'high-availability',
icon: 'cluster',
text: 'PMM HA',
url: `${PMM_NEW_NAV_GRAFANA_PATH}/high-availability`,
children: [
{
id: 'high-availability-health-dashboard',
text: 'Health Dashboard',
url: `${PMM_NEW_NAV_GRAFANA_PATH}/high-availability/overview`,
},
{
id: 'high-availability-identify-nodes',
icon: 'arrow-link',
text: 'Identify Nodes',
url: `${PMM_NEW_NAV_GRAFANA_PATH}/high-availability/identify-nodes`,
},
{
id: 'high-availability-review-alerts',
icon: 'arrow-link',
text: 'Review Alerts',
url: `${PMM_NEW_NAV_GRAFANA_PATH}/high-availability/node-status`,
},
],
};
6 changes: 6 additions & 0 deletions ui/apps/pmm/src/contexts/navigation/navigation.provider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
addConfiguration,
addDashboardItems,
addExplore,
addHighAvailability,
addUsersAndAccess,
} from './navigation.utils';
import { useUser } from 'contexts/user';
Expand Down Expand Up @@ -55,6 +56,11 @@ export const NavigationProvider: FC<PropsWithChildren> = ({ children }) => {

items.push(NAV_HOME_PAGE);

items.push(addHighAvailability());
items.push(addHighAvailability('at-risk'));
items.push(addHighAvailability('down'));
items.push(addHighAvailability('updating'));

items.push(NAV_DIVIDERS.home);

items.push(...addDashboardItems(currentServiceTypes, folders, user));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,17 @@ import {
NAV_ALERTS_SILENCES,
NAV_ALERTS_GROUPS,
NAV_VALKEY,
NAV_HIGH_AVAILABILITY,
NAV_USERS_AND_ACCESS,
NAV_ACCESS_CONTROL,
} from './navigation.constants';
import { CombinedSettings } from 'contexts/settings';
import { capitalize } from 'utils/text.utils';
import { DashboardFolder } from 'types/folders.types';
import { GetUpdatesResponse, UpdateStatus } from 'types/updates.types';
import { HighAvailabilityIcon } from 'components/ha-icon';
import { HighAvailabilityBadge } from 'components/ha-badge';
import { HighAvailabilityHealth } from 'types/high-availability.types';

export const addOtherDashboardsItem = (
rootNode: NavItem,
Expand Down Expand Up @@ -242,6 +246,18 @@ export const addConfiguration = (
return NAV_CONFIGURATION;
};

export const addHighAvailability = (
health: HighAvailabilityHealth = 'healthy'
): NavItem => {
const item = { ...NAV_HIGH_AVAILABILITY, id: `high-availability-${health}` };

item.badge = <HighAvailabilityBadge health={health} />;
item.icon = <HighAvailabilityIcon health={health} />;
item.badgeAlwaysVisible = true;

return item;
};

export const addUsersAndAccess = (settings?: CombinedSettings): NavItem => {
const children: NavItem[] = [...(NAV_USERS_AND_ACCESS.children || [])];

Expand Down
3 changes: 3 additions & 0 deletions ui/apps/pmm/src/icons/arrow-link.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
3 changes: 3 additions & 0 deletions ui/apps/pmm/src/icons/cluster.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 10 additions & 0 deletions ui/apps/pmm/src/icons/status-at-risk.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading