mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[SolutionSideNav] Add badge to all items except section header (#217301)
## Summary This PR adds the ability add badge to all side nav items, except section headers. Follow-up on https://github.com/elastic/kibana/pull/214854 
This commit is contained in:
parent
9342cff262
commit
0d84936259
5 changed files with 51 additions and 35 deletions
|
@ -24,6 +24,7 @@ import {
|
|||
EuiButton,
|
||||
} from '@elastic/eui';
|
||||
import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser';
|
||||
import { SubItemTitle } from './subitem_title';
|
||||
import { useNavigation as useServices } from '../../services';
|
||||
import { isActiveFromUrl } from '../../utils';
|
||||
import type { NavigateToUrlFn } from '../../types';
|
||||
|
@ -46,7 +47,11 @@ const getStyles = (euiTheme: EuiThemeComputed<{}>) => css`
|
|||
}
|
||||
`;
|
||||
|
||||
const getButtonStyles = (euiTheme: EuiThemeComputed<{}>, isActive: boolean) => css`
|
||||
const getButtonStyles = (
|
||||
euiTheme: EuiThemeComputed<{}>,
|
||||
isActive: boolean,
|
||||
withBadge?: boolean
|
||||
) => css`
|
||||
background-color: ${isActive ? transparentize(euiTheme.colors.lightShade, 0.5) : 'transparent'};
|
||||
transform: none !important; /* don't translateY 1px */
|
||||
color: inherit;
|
||||
|
@ -56,14 +61,21 @@ const getButtonStyles = (euiTheme: EuiThemeComputed<{}>, isActive: boolean) => c
|
|||
justify-content: flex-start;
|
||||
position: relative;
|
||||
}
|
||||
& .euiIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateY(50%);
|
||||
}
|
||||
${!withBadge
|
||||
? `
|
||||
& .euiIcon {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
top: 0;
|
||||
transform: translateY(50%);
|
||||
}
|
||||
`
|
||||
: `
|
||||
& .euiBetaBadge {
|
||||
margin-left: -${euiTheme.size.m};
|
||||
}
|
||||
`}
|
||||
`;
|
||||
|
||||
interface Props {
|
||||
item: ChromeProjectNavigationNode;
|
||||
navigateToUrl: NavigateToUrlFn;
|
||||
|
@ -74,7 +86,7 @@ export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, active
|
|||
const { euiTheme } = useEuiTheme();
|
||||
const { open: openPanel, close: closePanel, selectedNode } = usePanel();
|
||||
const { isSideNavCollapsed } = useServices();
|
||||
const { title, deepLink, children } = item;
|
||||
const { title, deepLink, children, withBadge } = item;
|
||||
const { id, path } = item;
|
||||
const href = deepLink?.url ?? item.href;
|
||||
const isNotMobile = useIsWithinMinBreakpoint('s');
|
||||
|
@ -89,7 +101,10 @@ export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, active
|
|||
getStyles(euiTheme)
|
||||
);
|
||||
|
||||
const buttonClassNames = classNames('sideNavItem', getButtonStyles(euiTheme, isActive));
|
||||
const buttonClassNames = classNames(
|
||||
'sideNavItem',
|
||||
getButtonStyles(euiTheme, isActive, withBadge)
|
||||
);
|
||||
|
||||
const dataTestSubj = classNames(`nav-item`, `nav-item-${path}`, {
|
||||
[`nav-item-deepLinkId-${deepLink?.id}`]: !!deepLink,
|
||||
|
@ -144,17 +159,17 @@ export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, active
|
|||
className={buttonClassNames}
|
||||
data-test-subj={dataTestSubj}
|
||||
>
|
||||
{title}
|
||||
{withBadge ? <SubItemTitle item={item} /> : title}
|
||||
</EuiButton>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<EuiFlexGroup alignItems="center" gutterSize="xs">
|
||||
<EuiFlexItem style={{ flexBasis: isIconVisible ? '80%' : '100%' }}>
|
||||
<EuiFlexItem css={{ flexBasis: isIconVisible ? '80%' : '100%' }}>
|
||||
<EuiListGroup gutterSize="none">
|
||||
<EuiListGroupItem
|
||||
label={title}
|
||||
label={withBadge ? <SubItemTitle item={item} /> : title}
|
||||
href={href}
|
||||
wrapText
|
||||
onClick={onLinkClick}
|
||||
|
@ -166,7 +181,7 @@ export const NavigationItemOpenPanel: FC<Props> = ({ item, navigateToUrl, active
|
|||
</EuiListGroup>
|
||||
</EuiFlexItem>
|
||||
{isIconVisible && (
|
||||
<EuiFlexItem grow={0} style={{ flexBasis: '15%' }}>
|
||||
<EuiFlexItem grow={0} css={{ flexBasis: '15%' }}>
|
||||
<EuiButtonIcon
|
||||
display={isExpanded ? 'base' : 'empty'}
|
||||
size="s"
|
||||
|
|
|
@ -421,7 +421,7 @@ function nodeToEuiCollapsibleNavProps(
|
|||
onClick,
|
||||
icon: navNode.icon,
|
||||
// @ts-expect-error title accepts JSX elements and they render correctly but the type definition expects a string
|
||||
title: !subItems && navNode.withBadge ? <SubItemTitle item={navNode} /> : navNode.title,
|
||||
title: navNode.withBadge ? <SubItemTitle item={navNode} /> : navNode.title,
|
||||
['data-test-subj']: dataTestSubj,
|
||||
iconProps: { size: deps.treeDepth === 0 ? 'm' : 's' },
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ import {
|
|||
import { css } from '@emotion/css';
|
||||
|
||||
import type { ChromeProjectNavigationNode } from '@kbn/core-chrome-browser';
|
||||
import { SubItemTitle } from '../subitem_title';
|
||||
import { PanelNavItem } from './panel_nav_item';
|
||||
|
||||
const accordionButtonClassName = 'sideNavPanelAccordion__button';
|
||||
|
@ -64,7 +65,7 @@ interface Props {
|
|||
|
||||
export const PanelGroup: FC<Props> = ({ navNode, isFirstInList, hasHorizontalRuleBefore }) => {
|
||||
const { euiTheme } = useEuiTheme();
|
||||
const { id, title, appendHorizontalRule, spaceBefore: _spaceBefore } = navNode;
|
||||
const { id, title, appendHorizontalRule, spaceBefore: _spaceBefore, withBadge } = navNode;
|
||||
const filteredChildren = navNode.children?.filter((child) => child.sideNavStatus !== 'hidden');
|
||||
const classNames = getClassnames(euiTheme);
|
||||
const hasTitle = !!title && title !== '';
|
||||
|
@ -83,21 +84,18 @@ export const PanelGroup: FC<Props> = ({ navNode, isFirstInList, hasHorizontalRul
|
|||
}
|
||||
}
|
||||
|
||||
const renderChildren = useCallback(
|
||||
({ parentIsAccordion } = { parentIsAccordion: false }) => {
|
||||
if (!filteredChildren) return null;
|
||||
const renderChildren = useCallback(() => {
|
||||
if (!filteredChildren) return null;
|
||||
|
||||
return filteredChildren.map((item, i) => {
|
||||
const isItem = item.renderAs === 'item' || !item.children;
|
||||
return isItem ? (
|
||||
<PanelNavItem key={item.id} item={item} parentIsAccordion={parentIsAccordion} />
|
||||
) : (
|
||||
<PanelGroup navNode={item} key={item.id} />
|
||||
);
|
||||
});
|
||||
},
|
||||
[filteredChildren]
|
||||
);
|
||||
return filteredChildren.map((item, i) => {
|
||||
const isItem = item.renderAs === 'item' || !item.children;
|
||||
return isItem ? (
|
||||
<PanelNavItem key={item.id} item={item} />
|
||||
) : (
|
||||
<PanelGroup navNode={item} key={item.id} />
|
||||
);
|
||||
});
|
||||
}, [filteredChildren]);
|
||||
|
||||
if (!filteredChildren?.length || !someChildIsVisible(filteredChildren)) {
|
||||
return null;
|
||||
|
@ -109,7 +107,7 @@ export const PanelGroup: FC<Props> = ({ navNode, isFirstInList, hasHorizontalRul
|
|||
{spaceBefore !== null && <EuiSpacer size={spaceBefore} />}
|
||||
<EuiAccordion
|
||||
id={id}
|
||||
buttonContent={title}
|
||||
buttonContent={withBadge ? <SubItemTitle item={navNode} /> : title}
|
||||
className={classNames.accordion}
|
||||
buttonClassName={accordionButtonClassName}
|
||||
data-test-subj={groupTestSubj}
|
||||
|
@ -120,7 +118,7 @@ export const PanelGroup: FC<Props> = ({ navNode, isFirstInList, hasHorizontalRul
|
|||
>
|
||||
<>
|
||||
{!firstChildIsGroup && <EuiSpacer size="s" />}
|
||||
{renderChildren({ parentIsAccordion: true })}
|
||||
{renderChildren()}
|
||||
</>
|
||||
</EuiAccordion>
|
||||
{appendHorizontalRule && <EuiHorizontalRule margin="xs" />}
|
||||
|
|
|
@ -19,10 +19,9 @@ import { usePanel } from './context';
|
|||
|
||||
interface Props {
|
||||
item: ChromeProjectNavigationNode;
|
||||
parentIsAccordion?: boolean;
|
||||
}
|
||||
|
||||
export const PanelNavItem: FC<Props> = ({ item, parentIsAccordion }) => {
|
||||
export const PanelNavItem: FC<Props> = ({ item }) => {
|
||||
const { navigateToUrl } = useServices();
|
||||
const { close: closePanel } = usePanel();
|
||||
const { id, icon, deepLink, openInNewTab, isExternalLink, renderItem } = item;
|
||||
|
@ -46,7 +45,7 @@ export const PanelNavItem: FC<Props> = ({ item, parentIsAccordion }) => {
|
|||
) : (
|
||||
<EuiListGroupItem
|
||||
key={id}
|
||||
label={parentIsAccordion ? <SubItemTitle item={item} /> : item.title}
|
||||
label={<SubItemTitle item={item} />}
|
||||
wrapText
|
||||
className={classNames(
|
||||
'sideNavPanelLink',
|
||||
|
|
|
@ -113,6 +113,7 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
|
|||
href: '/app/kibana',
|
||||
icon: 'iInCircle',
|
||||
isExternalLink: true,
|
||||
withBadge: true,
|
||||
},
|
||||
{
|
||||
id: 'item02',
|
||||
|
@ -229,6 +230,7 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
|
|||
title: 'Item 19',
|
||||
icon: 'iInCircle',
|
||||
renderAs: 'accordion',
|
||||
withBadge: true,
|
||||
children: [
|
||||
{
|
||||
id: 'sub1',
|
||||
|
@ -294,6 +296,7 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
|
|||
path: '',
|
||||
icon: 'iInCircle',
|
||||
renderAs: 'panelOpener',
|
||||
withBadge: true,
|
||||
children: [
|
||||
{
|
||||
id: 'sub1',
|
||||
|
@ -411,6 +414,7 @@ const generalLayoutNavTree: NavigationTreeDefinitionUI = {
|
|||
path: '',
|
||||
renderAs: 'accordion',
|
||||
icon: 'iInCircle',
|
||||
withBadge: true,
|
||||
children: [
|
||||
{
|
||||
id: 'item-beta',
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue