Remove feature flag and legacy navigation code

This commit removes the alertingNavigationV2 feature flag and all
legacy navigation code, making the V2 navigation the only option.

This simplifies the codebase by removing:
- Feature flag checks in backend and frontend
- buildAlertNavLinksLegacy function (114 lines)
- Legacy tab code in ContactPoints and NotificationPoliciesPage
- Related test code for legacy navigation

Backend changes:
- navtree.go: Remove feature flag check, delete legacy function
- navtree_alerting_test.go: Remove legacy tests, update V2 tests

Frontend changes:
- Home.tsx: Remove feature flag, Insights tab always hidden
- ContactPoints.tsx: Remove tabs, show only contact points
- NotificationPoliciesPage.tsx: Remove tabs, show only policies

This branch is designed for a one-time change to reduce change
surface compared to maintaining both legacy and V2 navigation.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
Alejandro Fraenkel
2026-01-12 19:19:59 +01:00
co-authored by Claude Sonnet 4.5
parent 774551589b
commit b3625b95e3
5 changed files with 16 additions and 463 deletions
+1 -121
View File
@@ -433,12 +433,7 @@ func (s *ServiceImpl) buildDashboardNavLinks(c *contextmodel.ReqContext) []*navt
}
func (s *ServiceImpl) buildAlertNavLinks(c *contextmodel.ReqContext) *navtree.NavLink {
//nolint:staticcheck // not yet migrated to OpenFeature
if !s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingNavigationV2) {
return s.buildAlertNavLinksLegacy(c)
}
// V2 Navigation - New grouped structure
// V2 Navigation - Grouped structure
hasAccess := ac.HasAccess(s.accessControl, c)
var alertChildNavs []*navtree.NavLink
@@ -640,121 +635,6 @@ func (s *ServiceImpl) buildAlertNavLinks(c *contextmodel.ReqContext) *navtree.Na
return nil
}
func (s *ServiceImpl) buildAlertNavLinksLegacy(c *contextmodel.ReqContext) *navtree.NavLink {
hasAccess := ac.HasAccess(s.accessControl, c)
var alertChildNavs []*navtree.NavLink
//nolint:staticcheck // not yet migrated to OpenFeature
if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingTriage) {
if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Alert activity", SubTitle: "Visualize active and pending alerts", Id: "alert-alerts", Url: s.cfg.AppSubURL + "/alerting/alerts", Icon: "bell", IsNew: true,
})
}
}
if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead), ac.EvalPermission(ac.ActionAlertingRuleExternalRead))) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Alert rules", SubTitle: "Rules that determine whether an alert will fire", Id: "alert-list", Url: s.cfg.AppSubURL + "/alerting/list", Icon: "list-ul",
})
}
contactPointsPerms := []ac.Evaluator{
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead),
ac.EvalPermission(ac.ActionAlertingReceiversRead),
ac.EvalPermission(ac.ActionAlertingReceiversReadSecrets),
ac.EvalPermission(ac.ActionAlertingReceiversCreate),
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesRead),
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesWrite),
ac.EvalPermission(ac.ActionAlertingNotificationsTemplatesDelete),
}
if hasAccess(ac.EvalAny(contactPointsPerms...)) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Contact points", SubTitle: "Choose how to notify your contact points when an alert instance fires", Id: "receivers", Url: s.cfg.AppSubURL + "/alerting/notifications",
Icon: "comment-alt-share",
})
}
if hasAccess(ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingNotificationsRead),
ac.EvalPermission(ac.ActionAlertingNotificationsExternalRead),
ac.EvalPermission(ac.ActionAlertingRoutesRead),
ac.EvalPermission(ac.ActionAlertingRoutesWrite),
ac.EvalPermission(ac.ActionAlertingNotificationsTimeIntervalsRead),
ac.EvalPermission(ac.ActionAlertingNotificationsTimeIntervalsWrite),
)) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Notification policies", SubTitle: "Determine how alerts are routed to contact points", Id: "am-routes", Url: s.cfg.AppSubURL + "/alerting/routes", Icon: "sitemap"})
}
if hasAccess(ac.EvalAny(
ac.EvalPermission(ac.ActionAlertingInstanceRead),
ac.EvalPermission(ac.ActionAlertingInstancesExternalRead),
ac.EvalPermission(ac.ActionAlertingSilencesRead),
)) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Silences", SubTitle: "Stop notifications from one or more alerting rules", Id: "silences", Url: s.cfg.AppSubURL + "/alerting/silences", Icon: "bell-slash"})
}
if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingInstanceRead), ac.EvalPermission(ac.ActionAlertingInstancesExternalRead))) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{Text: "Alert groups", SubTitle: "See grouped alerts with active notifications", Id: "groups", Url: s.cfg.AppSubURL + "/alerting/groups", Icon: "layer-group"})
}
//nolint:staticcheck // not yet migrated to OpenFeature
if s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingCentralAlertHistory) {
if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleRead))) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "History",
SubTitle: "View a history of all alert events generated by your Grafana-managed alert rules. All alert events are displayed regardless of whether silences or mute timings are set.",
Id: "alerts-history",
Url: s.cfg.AppSubURL + "/alerting/history",
Icon: "history",
})
}
}
//nolint:staticcheck // not yet migrated to OpenFeature
if c.GetOrgRole() == org.RoleAdmin && s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertRuleRestore) && s.features.IsEnabled(c.Req.Context(), featuremgmt.FlagAlertingRuleRecoverDeleted) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Recently deleted",
SubTitle: "Any items listed here for more than 30 days will be automatically deleted.",
Id: "alerts/recently-deleted",
Url: s.cfg.AppSubURL + "/alerting/recently-deleted",
})
}
if c.GetOrgRole() == org.RoleAdmin {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Settings", Id: "alerting-admin", Url: s.cfg.AppSubURL + "/alerting/admin",
Icon: "cog",
})
}
if hasAccess(ac.EvalAny(ac.EvalPermission(ac.ActionAlertingRuleCreate), ac.EvalPermission(ac.ActionAlertingRuleExternalWrite))) {
alertChildNavs = append(alertChildNavs, &navtree.NavLink{
Text: "Create alert rule", SubTitle: "Create an alert rule", Id: "alert",
Icon: "plus", Url: s.cfg.AppSubURL + "/alerting/new", HideFromTabs: true, IsCreateAction: true,
})
}
if len(alertChildNavs) > 0 {
var alertNav = navtree.NavLink{
Text: "Alerting",
SubTitle: "Learn about problems in your systems moments after they occur",
Id: navtree.NavIDAlerting,
Icon: "bell",
Children: alertChildNavs,
SortWeight: navtree.WeightAlerting,
Url: s.cfg.AppSubURL + "/alerting",
}
return &alertNav
}
return nil
}
func (s *ServiceImpl) buildDataConnectionsNavLink(c *contextmodel.ReqContext) *navtree.NavLink {
hasAccess := ac.HasAccess(s.accessControl, c)
@@ -83,88 +83,12 @@ func hasChildWithId(parent *navtree.NavLink, childId string) bool {
return false
}
func TestBuildAlertNavLinks_FeatureToggle(t *testing.T) {
func TestBuildAlertNavLinks(t *testing.T) {
reqCtx := setupTestContext()
permissions := fullPermissions()
t.Run("Should use legacy navigation when flag is off", func(t *testing.T) {
service := setupTestService(permissions) // No feature flags
navLink := service.buildAlertNavLinks(reqCtx)
require.NotNil(t, navLink)
require.Equal(t, "Alerting", navLink.Text)
require.Equal(t, navtree.NavIDAlerting, navLink.Id)
// Legacy structure: flat children without nested items
require.NotEmpty(t, navLink.Children)
alertList := findNavLink(navLink, "alert-list")
receivers := findNavLink(navLink, "receivers")
require.NotNil(t, alertList, "Should have alert-list in legacy navigation")
require.NotNil(t, receivers, "Should have receivers in legacy navigation")
require.Empty(t, alertList.Children, "Legacy items should not have nested children")
require.Empty(t, receivers.Children, "Legacy items should not have nested children")
})
t.Run("Should use V2 navigation when flag is on", func(t *testing.T) {
service := setupTestService(permissions, "alertingNavigationV2")
navLink := service.buildAlertNavLinks(reqCtx)
require.NotNil(t, navLink)
require.Equal(t, "Alerting", navLink.Text)
require.Equal(t, navtree.NavIDAlerting, navLink.Id)
// V2 structure: grouped parents with nested children
require.NotEmpty(t, navLink.Children)
// Verify all expected parent items exist with children
expectedParents := []string{"alert-rules", "notification-config", "insights", "alerting-settings"}
for _, parentId := range expectedParents {
parent := findNavLink(navLink, parentId)
require.NotNil(t, parent, "Should have %s parent in V2 navigation", parentId)
require.NotEmpty(t, parent.Children, "V2 parent %s should have children", parentId)
}
// Verify alert-rules has expected tab
alertRules := findNavLink(navLink, "alert-rules")
require.True(t, hasChildWithId(alertRules, "alert-rules-list"), "Should have alert-rules-list tab")
})
}
func TestBuildAlertNavLinks_Legacy(t *testing.T) {
reqCtx := setupTestContext()
t.Run("Should include all expected items in legacy navigation", func(t *testing.T) {
service := setupTestService(fullPermissions())
navLink := service.buildAlertNavLinksLegacy(reqCtx)
require.NotNil(t, navLink)
expectedIds := []string{"alert-list", "receivers", "am-routes", "alerting-admin"}
for _, expectedId := range expectedIds {
require.NotNil(t, findNavLink(navLink, expectedId), "Should have %s in legacy navigation", expectedId)
}
})
t.Run("Should respect permissions in legacy navigation", func(t *testing.T) {
limitedPermissions := []ac.Permission{
{Action: ac.ActionAlertingRuleRead, Scope: "*"},
}
limitedService := setupTestService(limitedPermissions)
navLink := limitedService.buildAlertNavLinksLegacy(reqCtx)
require.NotNil(t, navLink)
require.NotNil(t, findNavLink(navLink, "alert-list"), "Should have alert rules with read permission")
require.Nil(t, findNavLink(navLink, "receivers"), "Should not have contact points without notification permissions")
})
}
func TestBuildAlertNavLinks_V2(t *testing.T) {
reqCtx := setupTestContext()
allFeatureFlags := []string{"alertingNavigationV2", "alertingTriage", "alertingCentralAlertHistory", "alertRuleRestore", "alertingRuleRecoverDeleted"}
allFeatureFlags := []string{"alertingTriage", "alertingCentralAlertHistory", "alertRuleRestore", "alertingRuleRecoverDeleted"}
service := setupTestService(fullPermissions(), allFeatureFlags...)
t.Run("Should have correct parent structure in V2 navigation", func(t *testing.T) {
t.Run("Should have correct parent structure", func(t *testing.T) {
navLink := service.buildAlertNavLinks(reqCtx)
require.NotNil(t, navLink)
require.NotEmpty(t, navLink.Children)
@@ -173,7 +97,7 @@ func TestBuildAlertNavLinks_V2(t *testing.T) {
parentIds := []string{"alert-rules", "notification-config", "insights", "alerting-settings"}
for _, parentId := range parentIds {
parent := findNavLink(navLink, parentId)
require.NotNil(t, parent, "Should have parent %s in V2 navigation", parentId)
require.NotNil(t, parent, "Should have parent %s", parentId)
require.NotEmpty(t, parent.Children, "Parent %s should have children", parentId)
}
})
@@ -202,11 +126,11 @@ func TestBuildAlertNavLinks_V2(t *testing.T) {
}
})
t.Run("Should respect permissions in V2 navigation", func(t *testing.T) {
t.Run("Should respect permissions", func(t *testing.T) {
limitedPermissions := []ac.Permission{
{Action: ac.ActionAlertingRuleRead, Scope: "*"},
}
limitedService := setupTestService(limitedPermissions, "alertingNavigationV2")
limitedService := setupTestService(limitedPermissions)
navLink := limitedService.buildAlertNavLinks(reqCtx)
require.NotNil(t, navLink)
@@ -215,7 +139,7 @@ func TestBuildAlertNavLinks_V2(t *testing.T) {
require.Nil(t, findNavLink(navLink, "notification-config"), "Should not have notification-config without permissions")
})
t.Run("Should exclude future items from V2 navigation", func(t *testing.T) {
t.Run("Should exclude future items", func(t *testing.T) {
navLink := service.buildAlertNavLinks(reqCtx)
require.NotNil(t, navLink)
@@ -1,113 +1,11 @@
import { css } from '@emotion/css';
import { useState } from 'react';
import { GrafanaTheme2, UrlQueryMap } from '@grafana/data';
import { t } from '@grafana/i18n';
import { Tab, TabContent, TabsBar, useStyles2 } from '@grafana/ui';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
import { useMuteTimings } from 'app/features/alerting/unified/components/mute-timings/useMuteTimings';
import { NotificationPoliciesList } from 'app/features/alerting/unified/components/notification-policies/NotificationPoliciesList';
import { AlertmanagerAction, useAlertmanagerAbility } from 'app/features/alerting/unified/hooks/useAbilities';
import { AlertmanagerPageWrapper } from './components/AlertingPageWrapper';
import { GrafanaAlertmanagerWarning } from './components/GrafanaAlertmanagerWarning';
import { TimeIntervalsTable } from './components/mute-timings/MuteTimingsTable';
import { shouldUseAlertingNavigationV2 } from './featureToggles';
import { useNotificationConfigNav } from './navigation/useNotificationConfigNav';
import { useAlertmanager } from './state/AlertmanagerContext';
import { withPageErrorBoundary } from './withPageErrorBoundary';
enum ActiveTab {
NotificationPolicies = 'notification_policies',
TimeIntervals = 'time_intervals',
}
const NotificationPoliciesTabs = () => {
const styles = useStyles2(getStyles);
// Alertmanager logic and data hooks
const { selectedAlertmanager = '' } = useAlertmanager();
const [policiesSupported, canSeePoliciesTab] = useAlertmanagerAbility(AlertmanagerAction.ViewNotificationPolicyTree);
const [timingsSupported, canSeeTimingsTab] = useAlertmanagerAbility(AlertmanagerAction.ViewTimeInterval);
const availableTabs = [
canSeePoliciesTab && ActiveTab.NotificationPolicies,
canSeeTimingsTab && ActiveTab.TimeIntervals,
].filter((tab) => !!tab);
const { data: muteTimings = [] } = useMuteTimings({
alertmanager: selectedAlertmanager,
skip: !canSeeTimingsTab,
});
// Tab state management
const [queryParams, setQueryParams] = useQueryParams();
const { tab } = getActiveTabFromUrl(queryParams, availableTabs[0]);
const [activeTab, setActiveTab] = useState<ActiveTab>(tab);
const muteTimingsTabActive = activeTab === ActiveTab.TimeIntervals;
const policyTreeTabActive = activeTab === ActiveTab.NotificationPolicies;
const numberOfMuteTimings = muteTimings.length;
return (
<>
<GrafanaAlertmanagerWarning currentAlertmanager={selectedAlertmanager} />
<TabsBar>
{policiesSupported && canSeePoliciesTab && (
<Tab
label={t('alerting.notification-policies-tabs.label-notification-policies', 'Notification Policies')}
active={policyTreeTabActive}
onChangeTab={() => {
setActiveTab(ActiveTab.NotificationPolicies);
setQueryParams({ tab: ActiveTab.NotificationPolicies });
}}
/>
)}
{timingsSupported && canSeeTimingsTab && (
<Tab
label={t('alerting.notification-policies-tabs.label-time-intervals', 'Time intervals')}
active={muteTimingsTabActive}
counter={numberOfMuteTimings}
onChangeTab={() => {
setActiveTab(ActiveTab.TimeIntervals);
setQueryParams({ tab: ActiveTab.TimeIntervals });
}}
/>
)}
</TabsBar>
<TabContent className={styles.tabContent}>
{policyTreeTabActive && <NotificationPoliciesList />}
{muteTimingsTabActive && <TimeIntervalsTable />}
</TabContent>
</>
);
};
const getStyles = (theme: GrafanaTheme2) => ({
tabContent: css({
marginTop: theme.spacing(2),
}),
});
interface QueryParamValues {
tab: ActiveTab;
}
function getActiveTabFromUrl(queryParams: UrlQueryMap, defaultTab: ActiveTab): QueryParamValues {
let tab = defaultTab;
if (queryParams.tab === ActiveTab.NotificationPolicies) {
tab = ActiveTab.NotificationPolicies;
}
if (queryParams.tab === ActiveTab.TimeIntervals) {
tab = ActiveTab.TimeIntervals;
}
return {
tab,
};
}
const NotificationPoliciesContent = () => {
const { selectedAlertmanager = '' } = useAlertmanager();
return (
@@ -119,22 +17,13 @@ const NotificationPoliciesContent = () => {
};
function NotificationPoliciesPage() {
const useV2Nav = shouldUseAlertingNavigationV2();
const { navId, pageNav } = useNotificationConfigNav();
// In V2 mode, show only notification policies (no internal tabs)
if (useV2Nav) {
return (
<AlertmanagerPageWrapper navId={navId || 'am-routes'} pageNav={pageNav} accessType="notification">
<NotificationPoliciesContent />
</AlertmanagerPageWrapper>
);
}
// Legacy mode: Show internal tabs (backward compatible)
// Show only notification policies (no internal tabs)
// Time intervals are accessible via the sidebar navigation
return (
<AlertmanagerPageWrapper navId={navId || 'am-routes'} pageNav={pageNav} accessType="notification">
<NotificationPoliciesTabs />
<NotificationPoliciesContent />
</AlertmanagerPageWrapper>
);
}
@@ -1,31 +1,12 @@
import { css } from '@emotion/css';
import { useMemo } from 'react';
import { GrafanaTheme2 } from '@grafana/data';
import { Trans, t } from '@grafana/i18n';
import {
Alert,
Button,
EmptyState,
LinkButton,
LoadingPlaceholder,
Pagination,
Stack,
Tab,
TabContent,
TabsBar,
Text,
useStyles2,
} from '@grafana/ui';
import { Alert, Button, EmptyState, LinkButton, LoadingPlaceholder, Pagination, Stack } from '@grafana/ui';
import { contextSrv } from 'app/core/services/context_srv';
import { shouldUseK8sApi } from 'app/features/alerting/unified/utils/k8s/utils';
import { makeAMLink, stringifyErrorLike } from 'app/features/alerting/unified/utils/misc';
import { AccessControlAction } from 'app/types/accessControl';
import { shouldUseAlertingNavigationV2 } from '../../featureToggles';
import { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities';
import { usePagination } from '../../hooks/usePagination';
import { useURLSearchParams } from '../../hooks/useURLSearchParams';
import { useNotificationConfigNav } from '../../navigation/useNotificationConfigNav';
import { useAlertmanager } from '../../state/AlertmanagerContext';
import { isExtraConfig } from '../../utils/alertmanager/extraConfigs';
@@ -35,7 +16,6 @@ import { AlertmanagerPageWrapper } from '../AlertingPageWrapper';
import { GrafanaAlertmanagerWarning } from '../GrafanaAlertmanagerWarning';
import { ContactPoint } from './ContactPoint';
import { NotificationTemplates } from './NotificationTemplates';
import { ContactPointsFilter } from './components/ContactPointsFilter';
import { GlobalConfigAlert } from './components/GlobalConfigAlert';
import { useContactPointsWithStatus } from './useContactPoints';
@@ -43,11 +23,6 @@ import { useContactPointsSearch } from './useContactPointsSearch';
import { ALL_CONTACT_POINTS, useExportContactPoint } from './useExportContactPoint';
import { ContactPointWithMetadata } from './utils';
export enum ActiveTab {
ContactPoints = 'contact_points',
NotificationTemplates = 'templates',
}
const DEFAULT_PAGE_SIZE = 10;
const ContactPointsTab = () => {
@@ -157,122 +132,15 @@ const ContactPointsTab = () => {
);
};
const NotificationTemplatesTab = () => {
const [createTemplateSupported, createTemplateAllowed] = useAlertmanagerAbility(
AlertmanagerAction.CreateNotificationTemplate
);
return (
<Stack direction="column" gap={1}>
<Stack direction="row" alignItems="center" justifyContent="space-between">
<Text variant="body" color="secondary">
<Trans i18nKey="alerting.notification-templates-tab.create-notification-templates-customize-notifications">
Create notification templates to customize your notifications.
</Trans>
</Text>
{createTemplateSupported && (
<LinkButton
icon="plus"
variant="primary"
href="/alerting/notifications/templates/new"
disabled={!createTemplateAllowed}
>
<Trans i18nKey="alerting.notification-templates-tab.add-notification-template-group">
Add notification template group
</Trans>
</LinkButton>
)}
</Stack>
<NotificationTemplates />
</Stack>
);
};
const useTabQueryParam = (defaultTab: ActiveTab) => {
const [queryParams, setQueryParams] = useURLSearchParams();
const param = useMemo(() => {
const queryParam = queryParams.get('tab');
if (!queryParam || !Object.values(ActiveTab).map(String).includes(queryParam)) {
return defaultTab;
}
return queryParam || defaultTab;
}, [defaultTab, queryParams]);
const setParam = (tab: ActiveTab) => setQueryParams({ tab });
return [param, setParam] as const;
};
export const ContactPointsPageContents = () => {
const { selectedAlertmanager } = useAlertmanager();
const useV2Nav = shouldUseAlertingNavigationV2();
const styles = useStyles2(getStyles);
// All hooks must be called unconditionally before any early returns
const [, canViewContactPoints] = useAlertmanagerAbility(AlertmanagerAction.ViewContactPoint);
const [, canCreateContactPoints] = useAlertmanagerAbility(AlertmanagerAction.CreateContactPoint);
const [, showTemplatesTab] = useAlertmanagerAbility(AlertmanagerAction.ViewNotificationTemplate);
const showContactPointsTab = canViewContactPoints || canCreateContactPoints;
// Depending on permissions, user may not have access to all tabs,
// but we can default to picking the first one that they definitely _do_ have access to
const defaultTab = [
showContactPointsTab && ActiveTab.ContactPoints,
showTemplatesTab && ActiveTab.NotificationTemplates,
].filter((tab) => !!tab)[0];
const [activeTab, setActiveTab] = useTabQueryParam(defaultTab);
const { contactPoints } = useContactPointsWithStatus({
alertmanager: selectedAlertmanager!,
});
// In V2 navigation mode, show only contact points (no internal tabs)
// Show only contact points (no internal tabs)
// Templates are accessible via the sidebar navigation
if (useV2Nav) {
return (
<>
<GrafanaAlertmanagerWarning currentAlertmanager={selectedAlertmanager!} />
<ContactPointsTab />
</>
);
}
// Legacy mode: Show internal tabs (backward compatible)
const showingContactPoints = activeTab === ActiveTab.ContactPoints;
const showNotificationTemplates = activeTab === ActiveTab.NotificationTemplates;
return (
<>
<GrafanaAlertmanagerWarning currentAlertmanager={selectedAlertmanager!} />
<Stack direction="column">
<TabsBar>
{showContactPointsTab && (
<Tab
label={t('alerting.contact-points-page-contents.label-contact-points', 'Contact Points')}
active={showingContactPoints}
counter={contactPoints.length}
onChangeTab={() => setActiveTab(ActiveTab.ContactPoints)}
/>
)}
{showTemplatesTab && (
<Tab
label={t('alerting.contact-points-page-contents.label-notification-templates', 'Notification Templates')}
active={showNotificationTemplates}
onChangeTab={() => setActiveTab(ActiveTab.NotificationTemplates)}
/>
)}
</TabsBar>
<TabContent className={styles.tabContent}>
<Stack direction="column">
{showingContactPoints && <ContactPointsTab />}
{showNotificationTemplates && <NotificationTemplatesTab />}
</Stack>
</TabContent>
</Stack>
<ContactPointsTab />
</>
);
};
@@ -303,12 +171,6 @@ const ContactPointsList = ({ contactPoints, search, pageSize = DEFAULT_PAGE_SIZE
);
};
const getStyles = (theme: GrafanaTheme2) => ({
tabContent: css({
marginTop: theme.spacing(2),
}),
});
function ContactPointsPage() {
const { navId, pageNav } = useNotificationConfigNav();
return (
@@ -1,7 +1,6 @@
import { useMemo, useState } from 'react';
import { t } from '@grafana/i18n';
import { config } from '@grafana/runtime';
import { Box, Stack, Tab, TabContent, TabsBar } from '@grafana/ui';
import { AlertingPageWrapper } from '../components/AlertingPageWrapper';
@@ -15,9 +14,8 @@ import { PluginIntegrations } from './PluginIntegrations';
import SyntheticMonitoringCard from './SyntheticMonitoringCard';
function Home() {
// When V2 navigation is enabled, don't show Insights tab on Home page
// (Insights is available via the sidebar Insights menu instead)
const insightsEnabled = (insightsIsAvailable() || isLocalDevEnv()) && !config.featureToggles.alertingNavigationV2;
// Insights tab is not shown on Home page - Insights is available via the sidebar menu instead
const insightsEnabled = false;
const [activeTab, setActiveTab] = useState<'insights' | 'overview'>(insightsEnabled ? 'insights' : 'overview');
// Memoize the scene so it's only created once and properly initialized