Skip to content

Commit 617b722

Browse files
committed
2 parents 6c9d5ec + e73d82d commit 617b722

34 files changed

+713
-259
lines changed

packages/grafana-data/src/types/navModel.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ export interface NavModelItem extends NavLinkDTO {
3131
highlightId?: string;
3232
tabSuffix?: ComponentType<{ className?: string }>;
3333
showIconInNavbar?: boolean;
34+
// @Percona
35+
expanded?: boolean;
3436
}
3537

3638
export enum NavSection {

packages/grafana-ui/src/components/Collapse/CollapsableSection.tsx

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { css, cx } from '@emotion/css';
22
import { uniqueId } from 'lodash';
3-
import React, { FC, ReactNode, useRef, useState } from 'react';
3+
import React, { FC, ReactNode, useEffect, useRef, useState } from 'react';
44

55
import { GrafanaTheme2 } from '@grafana/data';
66

@@ -18,6 +18,8 @@ export interface Props {
1818
contentClassName?: string;
1919
loading?: boolean;
2020
labelId?: string;
21+
// @Percona
22+
controlled?: boolean;
2123
}
2224

2325
export const CollapsableSection: FC<Props> = ({
@@ -29,10 +31,17 @@ export const CollapsableSection: FC<Props> = ({
2931
children,
3032
labelId,
3133
loading = false,
34+
controlled = false,
3235
}) => {
3336
const [open, toggleOpen] = useState<boolean>(isOpen);
3437
const styles = useStyles2(collapsableSectionStyles);
3538

39+
useEffect(() => {
40+
if (controlled) {
41+
toggleOpen(isOpen);
42+
}
43+
}, [isOpen, controlled]);
44+
3645
const onClick = (e: React.MouseEvent) => {
3746
if (e.target instanceof HTMLElement && e.target.tagName === 'A') {
3847
return;

packages/grafana-ui/src/components/Icon/iconBundle.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,15 @@ import u1180 from '!!raw-loader!../../../../../public/img/icons/mono/percona-sur
184184
import u1181 from '!!raw-loader!../../../../../public/img/icons/mono/percona-temperature.svg';
185185
import u1182 from '!!raw-loader!../../../../../public/img/icons/mono/pmm-logo.svg';
186186
import u1183 from '!!raw-loader!../../../../../public/img/icons/mono/qan-logo.svg';
187+
import u1184 from '!!raw-loader!../../../../../public/img/icons/mono/percona-system.svg';
188+
import u1185 from '!!raw-loader!../../../../../public/img/icons/mono/percona-nav-overview.svg';
189+
import u1186 from '!!raw-loader!../../../../../public/img/icons/mono/percona-nav-summary.svg';
190+
import u1187 from '!!raw-loader!../../../../../public/img/icons/mono/percona-database-mysql.svg';
191+
import u1188 from '!!raw-loader!../../../../../public/img/icons/mono/percona-database-postgresql.svg';
192+
import u1189 from '!!raw-loader!../../../../../public/img/icons/mono/percona-database-mongodb.svg';
193+
import u1190 from '!!raw-loader!../../../../../public/img/icons/mono/percona-database-proxysql.svg';
194+
import u1191 from '!!raw-loader!../../../../../public/img/icons/mono/percona-database-haproxy.svg';
195+
187196
import { cacheStore } from 'react-inlinesvg';
188197

189198
export let cacheInitialized = false;
@@ -385,4 +394,12 @@ export function initIconCache() {
385394
cacheItem(u1181, 'mono/percona-temperature.svg');
386395
cacheItem(u1182, 'mono/pmm-logo.svg');
387396
cacheItem(u1183, 'mono/qan-logo.svg');
397+
cacheItem(u1184, 'mono/percona-system.svg');
398+
cacheItem(u1185, 'mono/percona-nav-overview.svg');
399+
cacheItem(u1186, 'mono/percona-nav-summary.svg');
400+
cacheItem(u1187, 'mono/percona-database-mysql.svg');
401+
cacheItem(u1188, 'mono/percona-database-postgresql.svg');
402+
cacheItem(u1189, 'mono/percona-database-mongodb.svg');
403+
cacheItem(u1190, 'mono/percona-database-proxysql.svg');
404+
cacheItem(u1191, 'mono/percona-database-haproxy.svg');
388405
}

packages/grafana-ui/src/components/Icon/utils.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,14 @@ const alwaysMonoIcons: IconName[] = [
2727
'percona-process',
2828
'percona-setting',
2929
'percona-database-checks',
30+
'percona-system',
31+
'percona-nav-overview',
32+
'percona-nav-summary',
33+
'percona-database-mysql',
34+
'percona-database-postgresql',
35+
'percona-database-mongodb',
36+
'percona-database-proxysql',
37+
'percona-database-haproxy',
3038
'pmm-logo',
3139
'qan-logo',
3240
];

packages/grafana-ui/src/types/icon.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,14 @@ export const getAvailableIcons = () =>
206206
'percona-setting',
207207
'percona-bell',
208208
'percona-bell-slash',
209+
'percona-system',
210+
'percona-nav-overview',
211+
'percona-nav-summary',
212+
'percona-database-mysql',
213+
'percona-database-postgresql',
214+
'percona-database-mongodb',
215+
'percona-database-proxysql',
216+
'percona-database-haproxy',
209217
'pmm-logo',
210218
'qan-logo',
211219
] as const;

pkg/api/index.go

Lines changed: 131 additions & 100 deletions
Large diffs are not rendered by default.

public/app/core/components/NavBar/NavBar.tsx

Lines changed: 50 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
import { css, cx } from '@emotion/css';
22
import { FocusScope } from '@react-aria/focus';
3+
import { useTour } from '@reactour/tour';
34
import { cloneDeep } from 'lodash';
4-
import React, { useState } from 'react';
5+
import React, { useEffect, useState } from 'react';
56
import { useDispatch, useSelector } from 'react-redux';
67
import { useLocation } from 'react-router-dom';
78

@@ -11,6 +12,7 @@ import { Icon, useTheme2 } from '@grafana/ui';
1112
import { updateNavIndex } from 'app/core/actions';
1213
import { Branding } from 'app/core/components/Branding/Branding';
1314
import { getKioskMode } from 'app/core/navigation/kiosk';
15+
import { initialState, updateNavTree } from 'app/core/reducers/navBarTree';
1416
import { getPerconaSettings, getPerconaUser } from 'app/percona/shared/core/selectors';
1517
import { KioskMode, StoreState } from 'app/types';
1618

@@ -39,9 +41,10 @@ import {
3941
buildIntegratedAlertingMenuItem,
4042
buildInventoryAndSettings,
4143
enrichConfigItems,
44+
enrichWithClickDispatch,
4245
enrichWithInteractionTracking,
4346
getActiveItem,
44-
isMatchOrChildMatch,
47+
isMatchOrInnerMatch,
4548
isSearchActive,
4649
SEARCH_ITEM_ID,
4750
} from './utils';
@@ -54,16 +57,18 @@ export const NavBar = React.memo(() => {
5457
const navBarTree = useSelector((state: StoreState) => state.navBarTree);
5558
const theme = useTheme2();
5659
const styles = getStyles(theme);
60+
const dispatchOffset = theme.transitions.duration.standard;
5761
const location = useLocation();
5862
const dispatch = useDispatch();
5963
const kiosk = getKioskMode();
6064
const { result } = useSelector(getPerconaSettings);
61-
const { sttEnabled, alertingEnabled, dbaasEnabled, backupEnabled } = result!;
65+
const { alertingEnabled } = result!;
6266
const { isPlatformUser, isAuthorized } = useSelector(getPerconaUser);
6367
const [showSwitcherModal, setShowSwitcherModal] = useState(false);
6468
const [menuOpen, setMenuOpen] = useState(false);
6569
const [menuAnimationInProgress, setMenuAnimationInProgress] = useState(false);
66-
const [menuIdOpen, setMenuIdOpen] = useState<string | undefined>(undefined);
70+
const [menuIdOpen, setMenuIdOpen] = useState<string | undefined>();
71+
const { isOpen: isTourOpen } = useTour();
6772

6873
const toggleSwitcherModal = () => {
6974
setShowSwitcherModal(!showSwitcherModal);
@@ -94,15 +99,19 @@ export const NavBar = React.memo(() => {
9499

95100
const coreItems = navTree
96101
.filter((item) => item.section === NavSection.Core)
97-
.map((item) => enrichWithInteractionTracking(item, menuOpen));
102+
.map((item) => enrichWithInteractionTracking(item, menuOpen))
103+
.map((item) => enrichWithClickDispatch(item, dispatch, dispatchOffset));
98104
const pluginItems = navTree
99105
.filter((item) => item.section === NavSection.Plugin)
100-
.map((item) => enrichWithInteractionTracking(item, menuOpen));
106+
.map((item) => enrichWithInteractionTracking(item, menuOpen))
107+
.map((item) => enrichWithClickDispatch(item, dispatch, dispatchOffset));
101108
const configItems = enrichConfigItems(
102109
navTree.filter((item) => item.section === NavSection.Config),
103110
location,
104111
toggleSwitcherModal
105-
).map((item) => enrichWithInteractionTracking(item, menuOpen));
112+
)
113+
.map((item) => enrichWithInteractionTracking(item, menuOpen))
114+
.map((item) => enrichWithClickDispatch(item, dispatch, dispatchOffset));
106115

107116
const activeItem = isSearchActive(location) ? searchItem : getActiveItem(navTree, location.pathname);
108117

@@ -120,32 +129,42 @@ export const NavBar = React.memo(() => {
120129
dispatch(updateNavIndex(PMM_ENVIRONMENT_OVERVIEW_PAGE));
121130

122131
// @PERCONA
123-
if (isPlatformUser) {
124-
coreItems.push(PMM_ENTITLEMENTS_PAGE);
125-
coreItems.push(PMM_TICKETS_PAGE);
126-
coreItems.push(PMM_ENVIRONMENT_OVERVIEW_PAGE);
127-
}
132+
useEffect(() => {
133+
const updatedNavTree = cloneDeep(initialState);
128134

129-
// @PERCONA
130-
if (isAuthorized) {
131-
buildInventoryAndSettings(configItems);
135+
const { sttEnabled, alertingEnabled, dbaasEnabled, backupEnabled } = result!;
132136

133-
if (alertingEnabled) {
134-
buildIntegratedAlertingMenuItem(coreItems);
137+
// @PERCONA
138+
if (isPlatformUser) {
139+
updatedNavTree.push(PMM_ENTITLEMENTS_PAGE);
140+
updatedNavTree.push(PMM_TICKETS_PAGE);
141+
updatedNavTree.push(PMM_ENVIRONMENT_OVERVIEW_PAGE);
135142
}
136143

137-
if (sttEnabled) {
138-
coreItems.push(PMM_STT_PAGE);
139-
}
144+
// @PERCONA
145+
if (isAuthorized) {
146+
buildInventoryAndSettings(updatedNavTree);
140147

141-
if (dbaasEnabled) {
142-
coreItems.push(PMM_DBAAS_PAGE);
143-
}
148+
if (alertingEnabled) {
149+
buildIntegratedAlertingMenuItem(updatedNavTree);
150+
}
144151

145-
if (backupEnabled) {
146-
coreItems.push(PMM_BACKUP_PAGE);
152+
if (sttEnabled) {
153+
updatedNavTree.push(PMM_STT_PAGE);
154+
}
155+
156+
if (dbaasEnabled) {
157+
updatedNavTree.push(PMM_DBAAS_PAGE);
158+
}
159+
160+
if (backupEnabled) {
161+
updatedNavTree.push(PMM_BACKUP_PAGE);
162+
}
147163
}
148-
}
164+
165+
dispatch(updateNavTree({ items: updatedNavTree }));
166+
// eslint-disable-next-line react-hooks/exhaustive-deps
167+
}, [result, isAuthorized, isPlatformUser]);
149168

150169
if (kiosk !== KioskMode.Off) {
151170
return null;
@@ -155,7 +174,8 @@ export const NavBar = React.memo(() => {
155174
<nav className={cx(styles.sidemenu, 'sidemenu')} data-testid="sidemenu" aria-label="Main menu">
156175
<NavBarContext.Provider
157176
value={{
158-
menuIdOpen: menuIdOpen,
177+
// Show MySQL item during onboarding tour
178+
menuIdOpen: isTourOpen ? 'mysql' : menuIdOpen,
159179
setMenuIdOpen: setMenuIdOpen,
160180
}}
161181
>
@@ -192,7 +212,7 @@ export const NavBar = React.memo(() => {
192212
{coreItems.map((link, index) => (
193213
<NavBarItem
194214
key={`${link.id}-${index}`}
195-
isActive={isMatchOrChildMatch(link, activeItem)}
215+
isActive={isMatchOrInnerMatch(link, activeItem)}
196216
link={{ ...link, subTitle: undefined }}
197217
/>
198218
))}
@@ -201,15 +221,15 @@ export const NavBar = React.memo(() => {
201221
pluginItems.map((link, index) => (
202222
<NavBarItem
203223
key={`${link.id}-${index}`}
204-
isActive={isMatchOrChildMatch(link, activeItem)}
224+
isActive={isMatchOrInnerMatch(link, activeItem)}
205225
link={link}
206226
/>
207227
))}
208228

209229
{configItems.map((link, index) => (
210230
<NavBarItem
211231
key={`${link.id}-${index}`}
212-
isActive={isMatchOrChildMatch(link, activeItem)}
232+
isActive={isMatchOrInnerMatch(link, activeItem)}
213233
reverseMenuDirection
214234
link={link}
215235
className={cx({ [styles.verticalSpacer]: index === 0 })}

public/app/core/components/NavBar/NavBarItem.tsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ const NavBarItem = ({ isActive = false, className, reverseMenuDirection = false,
8989
text={itemText}
9090
url={item.url}
9191
onClick={item.onClick}
92+
// @Percona
93+
showArrow={!!item.children && !isSection}
9294
styleOverrides={cx(styles.primaryText, { [styles.header]: isSection })}
9395
/>
9496
</Item>

public/app/core/components/NavBar/NavBarItemMenu.tsx

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import { GrafanaTheme2, NavMenuItemType, NavModelItem } from '@grafana/data';
1010
import { useTheme2 } from '@grafana/ui';
1111

1212
import { NavBarItemMenuItem } from './NavBarItemMenuItem';
13-
import { NavBarScrollContainer } from './NavBarScrollContainer';
1413
import { useNavBarItemMenuContext } from './context';
1514
import menuItemTranslations from './navBarItem-translations';
1615
import { getNavModelItemKey } from './utils';
@@ -76,14 +75,21 @@ export function NavBarItemMenu(props: NavBarItemMenuProps): ReactElement | null
7675
</li>
7776
);
7877

79-
const contents = [itemComponents, subTitleComponent];
80-
const contentComponent = (
81-
<NavBarScrollContainer key="scrollContainer">
82-
{reverseMenuDirection ? contents.reverse() : contents}
83-
</NavBarScrollContainer>
84-
);
78+
// @Percona
79+
//
80+
// Scrollcontainer prevented nested navigation from working
81+
// as it was hiding the expanded menus to the left
82+
//
83+
// const contents = [itemComponents, subTitleComponent];
84+
// const contentComponent = (
85+
// <NavBarScrollContainer key="scrollContainer">
86+
// {reverseMenuDirection ? contents.reverse() : contents}
87+
// </NavBarScrollContainer>
88+
// );
89+
//
90+
// const menu = [headerComponent, contentComponent];
8591

86-
const menu = [headerComponent, contentComponent];
92+
const menu = [headerComponent, itemComponents, subTitleComponent];
8793

8894
return (
8995
<ul className={styles.menu} ref={ref} {...mergeProps(menuProps, contextMenuProps)} tabIndex={menuHasFocus ? 0 : -1}>

0 commit comments

Comments
 (0)