Chore: Remove pinNavItems feature toggle (#113855)

This commit is contained in:
Tom Ratcliffe
2025-11-17 12:12:47 +00:00
committed by GitHub
parent 6f8b4032c2
commit 77dac4210f
12 changed files with 24 additions and 60 deletions
@@ -53,7 +53,6 @@ Most [generally available](https://grafana.com/docs/release-life-cycle/#general-
| `cloudWatchNewLabelParsing` | Updates CloudWatch label parsing to be more accurate | Yes |
| `pluginProxyPreserveTrailingSlash` | Preserve plugin proxy trailing slash. | |
| `azureMonitorPrometheusExemplars` | Allows configuration of Azure Monitor as a data source that can provide Prometheus exemplars | Yes |
| `pinNavItems` | Enables pinning of nav items | Yes |
| `ssoSettingsLDAP` | Use the new SSO Settings API to configure LDAP | Yes |
| `cloudWatchRoundUpEndTime` | Round up end time for metric queries to the next minute to avoid missing data | Yes |
| `newFiltersUI` | Enables new combobox style UI for the Ad hoc filters variable in scenes architecture | Yes |
-5
View File
@@ -566,11 +566,6 @@ export interface FeatureToggles {
*/
azureMonitorPrometheusExemplars?: boolean;
/**
* Enables pinning of nav items
* @default true
*/
pinNavItems?: boolean;
/**
* Enables the gRPC server for authorization
*/
authZGRPCServer?: boolean;
-7
View File
@@ -975,13 +975,6 @@ var (
Owner: grafanaPartnerPluginsSquad,
Expression: "true", // enabled by default
},
{
Name: "pinNavItems",
Description: "Enables pinning of nav items",
Stage: FeatureStageGeneralAvailability,
Owner: grafanaFrontendSearchNavOrganise,
Expression: "true", // enabled by default
},
{
Name: "authZGRPCServer",
Description: "Enables the gRPC server for authorization",
-1
View File
@@ -127,7 +127,6 @@ preserveDashboardStateWhenNavigating,experimental,@grafana/dashboards-squad,fals
alertingCentralAlertHistory,experimental,@grafana/alerting-squad,false,false,true
pluginProxyPreserveTrailingSlash,GA,@grafana/plugins-platform-backend,false,false,false
azureMonitorPrometheusExemplars,GA,@grafana/partner-datasources,false,false,false
pinNavItems,GA,@grafana/grafana-search-navigate-organise,false,false,false
authZGRPCServer,experimental,@grafana/identity-access-team,false,false,false
ssoSettingsLDAP,GA,@grafana/identity-access-team,false,true,false
zanzana,experimental,@grafana/identity-access-team,false,false,false
1 Name Stage Owner requiresDevMode RequiresRestart FrontendOnly
127 alertingCentralAlertHistory experimental @grafana/alerting-squad false false true
128 pluginProxyPreserveTrailingSlash GA @grafana/plugins-platform-backend false false false
129 azureMonitorPrometheusExemplars GA @grafana/partner-datasources false false false
pinNavItems GA @grafana/grafana-search-navigate-organise false false false
130 authZGRPCServer experimental @grafana/identity-access-team false false false
131 ssoSettingsLDAP GA @grafana/identity-access-team false true false
132 zanzana experimental @grafana/identity-access-team false false false
-4
View File
@@ -519,10 +519,6 @@ const (
// Allows configuration of Azure Monitor as a data source that can provide Prometheus exemplars
FlagAzureMonitorPrometheusExemplars = "azureMonitorPrometheusExemplars"
// FlagPinNavItems
// Enables pinning of nav items
FlagPinNavItems = "pinNavItems"
// FlagAuthZGRPCServer
// Enables the gRPC server for authorization
FlagAuthZGRPCServer = "authZGRPCServer"
+1
View File
@@ -3084,6 +3084,7 @@
"name": "pinNavItems",
"resourceVersion": "1762958248290",
"creationTimestamp": "2024-06-10T11:40:03Z",
"deletionTimestamp": "2025-11-13T14:52:10Z",
"annotations": {
"grafana.app/updatedTimestamp": "2025-11-12 14:37:28.29086 +0000 UTC"
}
+1 -6
View File
@@ -24,8 +24,6 @@ import (
"github.com/grafana/grafana/pkg/services/star"
"github.com/grafana/grafana/pkg/services/supportbundles/supportbundlesimpl"
"github.com/grafana/grafana/pkg/setting"
"github.com/open-feature/go-sdk/openfeature"
)
type ServiceImpl struct {
@@ -86,7 +84,6 @@ func ProvideService(cfg *setting.Cfg, accessControl ac.AccessControl, pluginStor
func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, prefs *pref.Preference) (*navtree.NavTreeRoot, error) {
hasAccess := ac.HasAccess(s.accessControl, c)
treeRoot := &navtree.NavTreeRoot{}
ctx := c.Req.Context()
treeRoot.AddSection(s.getHomeNode(c, prefs))
@@ -188,9 +185,7 @@ func (s *ServiceImpl) GetNavTree(c *contextmodel.ReqContext, prefs *pref.Prefere
treeRoot.RemoveSectionByID(navtree.NavIDCfg)
}
flagDetails, err := openfeature.NewDefaultClient().BooleanValueDetails(ctx, featuremgmt.FlagPinNavItems, true, openfeature.TransactionContext(ctx))
s.log.Debug("flag evaluation: ", "flagDetails", flagDetails, "err", err)
if flagDetails.Value && c.IsSignedIn {
if c.IsSignedIn {
treeRoot.AddSection(&navtree.NavLink{
Text: "Bookmarks",
Id: navtree.NavIDBookmarks,
@@ -7,7 +7,7 @@ import { usePatchUserPreferencesMutation } from '@grafana/api-clients/rtkq/legac
import { GrafanaTheme2, NavModelItem } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '@grafana/i18n';
import { config, reportInteraction } from '@grafana/runtime';
import { reportInteraction } from '@grafana/runtime';
import { ScrollContainer, useStyles2 } from '@grafana/ui';
import { useGrafana } from 'app/core/context/GrafanaContext';
import { setBookmark } from 'app/core/reducers/navBarTree';
@@ -40,25 +40,23 @@ export const MegaMenu = memo(
.filter((item) => item.id !== 'profile' && item.id !== 'help')
.map((item) => enrichWithInteractionTracking(item, state.megaMenuDocked));
if (config.featureToggles.pinNavItems) {
const bookmarksItem = navItems.find((item) => item.id === 'bookmarks');
if (bookmarksItem) {
// Add children to the bookmarks section
bookmarksItem.children = pinnedItems.reduce((acc: NavModelItem[], url) => {
const item = findByUrl(navItems, url);
if (!item) {
return acc;
}
const newItem = {
id: item.id,
text: item.text,
url: item.url,
parentItem: { id: 'bookmarks', text: 'Bookmarks' },
};
acc.push(enrichWithInteractionTracking(newItem, state.megaMenuDocked));
const bookmarksItem = navItems.find((item) => item.id === 'bookmarks');
if (bookmarksItem) {
// Add children to the bookmarks section
bookmarksItem.children = pinnedItems.reduce((acc: NavModelItem[], url) => {
const item = findByUrl(navItems, url);
if (!item) {
return acc;
}, []);
}
}
const newItem = {
id: item.id,
text: item.text,
url: item.url,
parentItem: { id: 'bookmarks', text: 'Bookmarks' },
};
acc.push(enrichWithInteractionTracking(newItem, state.megaMenuDocked));
return acc;
}, []);
}
const activeItem = getActiveItem(navItems, state.sectionNav.node, location.pathname);
@@ -85,8 +83,8 @@ export const MegaMenu = memo(
);
const onPinItem = (item: NavModelItem) => {
const url = item.url;
if (url && config.featureToggles.pinNavItems) {
const { url } = item;
if (url) {
const isSaved = isPinned(url);
const newItems = isSaved ? pinnedItems.filter((i) => url !== i) : [...pinnedItems, url];
const interactionName = isSaved ? 'grafana_nav_item_unpinned' : 'grafana_nav_item_pinned';
@@ -4,7 +4,6 @@ import * as React from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { selectors } from '@grafana/e2e-selectors';
import { t } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Icon, IconButton, Link, useTheme2 } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
@@ -39,7 +38,6 @@ export function MegaMenuItemText({ children, isActive, onClick, target, url, onP
<div
className={cx(styles.wrapper, {
[styles.wrapperActive]: isActive,
[styles.wrapperBookmark]: config.featureToggles.pinNavItems,
})}
>
<LinkComponent
@@ -52,7 +50,7 @@ export function MegaMenuItemText({ children, isActive, onClick, target, url, onP
>
{linkContent}
</LinkComponent>
{config.featureToggles.pinNavItems && contextSrv.isSignedIn && url && url !== '/bookmarks' && (
{contextSrv.isSignedIn && url && url !== '/bookmarks' && (
<IconButton
name="bookmark"
className={'pin-icon'}
@@ -77,8 +75,6 @@ const getStyles = (theme: GrafanaTheme2, isActive: Props['isActive']) => ({
justifyContent: 'space-between',
width: '100%',
height: '100%',
}),
wrapperBookmark: css({
'.pin-icon': {
visibility: 'hidden',
},
@@ -1,7 +1,6 @@
import { useMemo } from 'react';
import { useGetUserPreferencesQuery } from '@grafana/api-clients/rtkq/legacy/preferences';
import { config } from '@grafana/runtime';
import { contextSrv } from '../../../services/context_srv';
@@ -9,8 +8,5 @@ export const usePinnedItems = () => {
const preferences = useGetUserPreferencesQuery(undefined, { skip: !contextSrv.user.isSignedIn });
const pinnedItems = useMemo(() => preferences.data?.navbar?.bookmarkUrls || [], [preferences]);
if (config.featureToggles.pinNavItems) {
return pinnedItems;
}
return [];
return pinnedItems;
};
@@ -61,8 +61,7 @@ export const enrichWithInteractionTracking = (
reportInteraction('grafana_navigation_item_clicked', {
path: newItem.url ?? newItem.id,
menuIsDocked: megaMenuDockedState,
itemIsBookmarked: Boolean(config.featureToggles.pinNavItems && newItem?.parentItem?.id === 'bookmarks'),
bookmarkToggleOn: Boolean(config.featureToggles.pinNavItems),
itemIsBookmarked: newItem?.parentItem?.id === 'bookmarks',
isNew,
});
onClick?.();
-3
View File
@@ -52,9 +52,6 @@ const navTreeSlice = createSlice({
}
},
setBookmark: (state, action: PayloadAction<{ item: NavModelItem; isSaved: boolean }>) => {
if (!config.featureToggles.pinNavItems) {
return;
}
const bookmarks = state.find((navItem) => navItem.id === 'bookmarks');
const { item, isSaved } = action.payload;
if (bookmarks) {