diff --git a/public/app/features/alerting/unified/components/notification-policies/NotificationPoliciesList.tsx b/public/app/features/alerting/unified/components/notification-policies/NotificationPoliciesList.tsx
index dccaafedd2f..2e0a734a1ed 100644
--- a/public/app/features/alerting/unified/components/notification-policies/NotificationPoliciesList.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/NotificationPoliciesList.tsx
@@ -99,7 +99,6 @@ export const NotificationPoliciesList = () => {
}
return;
}, [defaultPolicy]);
- const routeProvenance = defaultPolicy?.provenance;
// useAsync could also work but it's hard to wait until it's done in the tests
// Combining with useEffect gives more predictable results because the condition is in useEffect
@@ -245,7 +244,6 @@ export const NotificationPoliciesList = () => {
currentRoute={defaults(rootRoute, TIMING_OPTIONS_DEFAULTS)}
contactPointsState={contactPointsState.receivers}
readOnly={!hasConfigurationAPI}
- provenance={routeProvenance}
alertManagerSourceName={selectedAlertmanager}
onAddPolicy={openAddModal}
onEditPolicy={openEditModal}
diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
index 1bec449dd6f..1cf56f156e2 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Policy.test.tsx
@@ -11,6 +11,7 @@ import {
AlertmanagerGroup,
MatcherOperator,
ObjectMatcher,
+ ROUTES_META_SYMBOL,
RouteWithID,
} from 'app/plugins/datasource/alertmanager/types';
@@ -338,6 +339,7 @@ describe('Policy', () => {
id: 'test-route',
receiver: 'test-receiver',
routes: [],
+ [ROUTES_META_SYMBOL]: { provenance: KnownProvenance.File },
};
renderPolicy(
@@ -351,7 +353,6 @@ describe('Policy', () => {
onAddPolicy={noop}
onDeletePolicy={noop}
onShowAlertInstances={noop}
- provenance={KnownProvenance.File}
/>
);
@@ -364,6 +365,7 @@ describe('Policy', () => {
id: 'test-route',
receiver: 'test-receiver',
routes: [],
+ [ROUTES_META_SYMBOL]: { provenance: KnownProvenance.ConvertedPrometheus },
};
renderPolicy(
@@ -377,13 +379,38 @@ describe('Policy', () => {
onAddPolicy={noop}
onDeletePolicy={noop}
onShowAlertInstances={noop}
- provenance={KnownProvenance.ConvertedPrometheus}
/>
);
const badge = screen.getByText('Imported');
expect(badge).toBeInTheDocument();
});
+
+ it('correctly identifies provisioned status from ROUTES_META_SYMBOL', () => {
+ const mockRoute: RouteWithID = {
+ id: 'test-route',
+ receiver: 'test-receiver',
+ routes: [],
+ [ROUTES_META_SYMBOL]: { provenance: KnownProvenance.File },
+ };
+
+ renderPolicy(
+
+ );
+
+ expect(screen.getByText('Provisioned')).toBeInTheDocument();
+ // Verify add/edit buttons are disabled
+ expect(screen.getByRole('button', { name: /new child policy/i })).toBeDisabled();
+ });
});
// Doesn't matter which path the routes use, it just needs to match the initialEntries history entry to render the element
@@ -510,13 +537,17 @@ describe('useCreateDropdownMenuActions', () => {
[true, true],
[true, true],
]);
+ // Create route with provenance in metadata or top-level to match real usage
+ const routeWithProvenance: RouteWithID = provenance
+ ? { ...currentRoute, [ROUTES_META_SYMBOL]: { provenance } }
+ : currentRoute;
const { result } = renderHook(() =>
useCreateDropdownMenuActions(
isAutoGenerated,
isDefaultPolicy,
provenance,
openDetailModal,
- currentRoute,
+ routeWithProvenance,
toggleShowExportDrawer,
onDeletePolicy
)
diff --git a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
index adb537b16a3..def301c6df8 100644
--- a/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
+++ b/public/app/features/alerting/unified/components/notification-policies/Policy.tsx
@@ -62,7 +62,6 @@ interface PolicyComponentProps {
receivers?: Receiver[];
contactPointsState?: ReceiversState;
readOnly?: boolean;
- provenance?: string;
inheritedProperties?: InheritableProperties;
routesMatchingFilters?: RoutesMatchingFilters;
@@ -90,7 +89,6 @@ const Policy = (props: PolicyComponentProps) => {
receivers = [],
contactPointsState,
readOnly = false,
- provenance,
alertManagerSourceName,
currentRoute,
inheritedProperties,
@@ -109,7 +107,8 @@ const Policy = (props: PolicyComponentProps) => {
const styles = useStyles2(getStyles);
- // Compute provisioned status from provenance
+ // Derive provenance from route metadata or top-level (consistent with child handling)
+ const provenance = currentRoute[ROUTES_META_SYMBOL]?.provenance ?? currentRoute.provenance;
const provisioned = isProvisionedResource(provenance);
const contactPoint = currentRoute.receiver;
@@ -364,9 +363,6 @@ const Policy = (props: PolicyComponentProps) => {
then the child policy should not be editable either */
const isThisChildReadOnly = readOnly || provisioned || isAutoGenerated;
- // Extract provenance from child route (can be in metadata symbol or top-level)
- const childProvenance = child[ROUTES_META_SYMBOL]?.provenance ?? child.provenance;
-
return (
{
routesMatchingFilters={routesMatchingFilters}
matchingInstancesPreview={matchingInstancesPreview}
isAutoGenerated={isThisChildAutoGenerated}
- provenance={childProvenance}
/>
);
})}