FS: Apply versionString in help menu in frontend (#112958)

Set version in help menu in the frontend instead
This commit is contained in:
Josh Hunt 2025-10-24 17:42:42 +01:00 committed by GitHub
parent 9b7c68c994
commit 59bfb44a50
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 66 additions and 37 deletions

View File

@ -216,7 +216,6 @@ func (hs *HTTPServer) setIndexViewData(c *contextmodel.ReqContext) (*dtos.IndexV
hs.HooksService.RunIndexDataHooks(&data, c)
data.NavTree.ApplyCostManagementIA()
data.NavTree.ApplyHelpVersion(data.Settings.BuildInfo.VersionString) // RunIndexDataHooks can modify the version string
data.NavTree.Sort()
return &data, nil

View File

@ -158,14 +158,6 @@ func Sort(nodes []*NavLink) {
}
}
func (root *NavTreeRoot) ApplyHelpVersion(version string) {
helpNode := root.FindById("help")
if helpNode != nil {
helpNode.SubTitle = version
}
}
func (root *NavTreeRoot) ApplyCostManagementIA() {
orgAdminNode := root.FindById(NavIDCfg)
var costManagementApp *NavLink

View File

@ -1,7 +1,10 @@
import { cloneDeep } from 'lodash';
import { NavModelItem } from '@grafana/data';
import { config } from '@grafana/runtime';
import { ContextSrv, setContextSrv } from 'app/core/services/context_srv';
import { enrichHelpItem, getActiveItem, findByUrl } from './utils';
import { getEnrichedHelpItem, getActiveItem, findByUrl } from './utils';
const starredDashboardUid = 'foo';
const mockNavTree: NavModelItem[] = [
@ -67,40 +70,62 @@ jest.mock('../../../app_events', () => ({
}));
describe('enrichConfigItems', () => {
let mockHelpNode: NavModelItem;
let mockHelpNode: NavModelItem = {
id: 'help',
text: 'Help',
};
let originalBuildInfo = { ...config.buildInfo };
beforeEach(() => {
mockHelpNode = {
id: 'help',
text: 'Help',
};
beforeAll(() => {
config.buildInfo.versionString = '9.0.0-test';
});
afterAll(() => {
config.buildInfo = originalBuildInfo;
});
it('enhances the help node with extra child links', () => {
const contextSrv = new ContextSrv();
setContextSrv(contextSrv);
const helpNode = enrichHelpItem(mockHelpNode);
expect(helpNode!.children).toContainEqual(
const helpNode = getEnrichedHelpItem(mockHelpNode);
expect(helpNode.children).toContainEqual(
expect.objectContaining({
text: 'Documentation',
})
);
expect(helpNode!.children).toContainEqual(
expect(helpNode.children).toContainEqual(
expect.objectContaining({
text: 'Support',
})
);
expect(helpNode!.children).toContainEqual(
expect(helpNode.children).toContainEqual(
expect.objectContaining({
text: 'Community',
})
);
expect(helpNode!.children).toContainEqual(
expect(helpNode.children).toContainEqual(
expect.objectContaining({
text: 'Keyboard shortcuts',
})
);
});
it('adds the version string as subtitle', () => {
const helpNode = getEnrichedHelpItem(mockHelpNode);
expect(helpNode.subTitle).toBe(config.buildInfo.versionString);
});
it("doesn't mutate the original help node", () => {
const originalHelpNode = cloneDeep(mockHelpNode);
const newHelpNode = getEnrichedHelpItem(mockHelpNode);
// The mockHelpNode should remain deeply equal to the clone we made of it
expect(mockHelpNode).toEqual(originalHelpNode);
// The new node should have a different identity than the original
expect(newHelpNode).not.toBe(mockHelpNode);
expect(newHelpNode.children).not.toBe(mockHelpNode.children);
});
});
describe('getActiveItem', () => {

View File

@ -13,14 +13,21 @@ import { HelpModal } from '../../help/HelpModal';
import { DOCK_MENU_BUTTON_ID, MEGA_MENU_HEADER_TOGGLE_ID } from './MegaMenuHeader';
export const enrichHelpItem = (helpItem: NavModelItem) => {
const emitOpenShortcutsModal = () => {
appEvents.publish(new ShowModalReactEvent({ component: HelpModal }));
};
export const getEnrichedHelpItem = (helpItem: NavModelItem): NavModelItem => {
let menuItems = helpItem.children || [];
if (helpItem.id === 'help') {
const onOpenShortcuts = () => {
appEvents.publish(new ShowModalReactEvent({ component: HelpModal }));
};
helpItem.children = [
if (helpItem.id !== 'help') {
return helpItem;
}
return {
...helpItem,
subTitle: config.buildInfo.versionString,
children: [
...menuItems,
...getFooterLinks(),
...getEditionAndUpdateLinks(),
@ -28,11 +35,10 @@ export const enrichHelpItem = (helpItem: NavModelItem) => {
id: 'keyboard-shortcuts',
text: t('nav.help/keyboard-shortcuts', 'Keyboard shortcuts'),
icon: 'keyboard',
onClick: onOpenShortcuts,
onClick: emitOpenShortcutsModal,
},
];
}
return helpItem;
],
};
};
export const enrichWithInteractionTracking = (

View File

@ -1,11 +1,18 @@
import { cloneDeep } from 'lodash';
import { useMemo } from 'react';
import { NavModelItem } from '@grafana/data';
import { useSelector } from 'app/types/store';
import { enrichHelpItem } from '../MegaMenu/utils';
import { getEnrichedHelpItem } from '../MegaMenu/utils';
export function useHelpNode() {
export function useHelpNode(): NavModelItem | undefined {
const navIndex = useSelector((state) => state.navIndex);
const helpNode = cloneDeep(navIndex['help']);
return helpNode ? enrichHelpItem(helpNode) : undefined;
const helpNode = useMemo(() => {
const helpNode = cloneDeep(navIndex['help']);
return helpNode ? getEnrichedHelpItem(helpNode) : undefined;
}, [navIndex]);
return helpNode;
}

View File

@ -2,7 +2,7 @@ import { useMemo } from 'react';
import { NavModelItem } from '@grafana/data';
import { t } from '@grafana/i18n';
import { enrichHelpItem } from 'app/core/components/AppChrome/MegaMenu/utils';
import { getEnrichedHelpItem } from 'app/core/components/AppChrome/MegaMenu/utils';
import {
shouldRenderInviteUserButton,
performInviteUserClick,
@ -25,7 +25,7 @@ function navTreeToActions(navTree: NavModelItem[], parents: NavModelItem[] = [])
for (let navItem of navTree) {
// help node needs enriching with the frontend links
if (navItem.id === 'help') {
navItem = enrichHelpItem({ ...navItem });
navItem = getEnrichedHelpItem({ ...navItem });
delete navItem.url;
}
const { url, target, text, isCreateAction, children, onClick, keywords } = navItem;