Files
grafana/public/app/features/alerting/unified/plugins/useRulePluginLinkExtensions.ts
Konrad Lalik 3e15459d20 Alerting: Enhance Ruler and Prometheus group synchronization (#99012)
* Add group actions menu

* Refactor modals to accept raw ruler group

* Use prometheus and ruler responses to dispaly GMA rules in the hierarchical view

* Add groups loader component for data source managed rules

* Improve rules matching algorithm for the search results

* Use plus and minus icons for reconciliation state

* loading spinner WIP for operations / transactions

* update comment

* Use ruler rules order when displaying a group, change rurler preload behaviour

* Add ruler-based ordering for GMA rules

* Refactor ruler API mocking

* Refactor rule components to accept ruler only rules

* Add tests for GrafanaGroupLoader

* Add tests for vanilla prom groups

* Unify data matching code, add tests for DS groups loader

* Fix errors after rebasing

* Improve handling of ruler group absence

* Fix cache key

* Add group action buttons for the new group pages

* Add new rule action buttons to the new list page

* Address PR feeback, component renaming, missing translations

* Unify groups and rules links and actions

* Fix new rule button

* Add rule list action buttons tests

* Fix lint errors

* Add redirect to rule details page on save

* Update FilterView tests

* Fix imports and remove unused code

* Improve type definitions, add pooling to Prom hooks, add inline docs

* Remove unused code of group modals

* Update translations

* Disable cache population for filter-view generators

* Add consistency check Alert to the RuleViewer when V2 list is enabled

* Disable UI errors in prom generator

* Improve missing datasouce handling

* Add missing translations

* Improve group loader tests, remove unused code

* Enhance Prometheus API query to include notification options

* Improve error handling, remove consistency check for vanilla prom data sources

* Address PR feedback, add new version of the useHasRuler hook

---------

Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
2025-04-01 09:58:09 +02:00

106 lines
3.2 KiB
TypeScript

import { useMemo, useRef } from 'react';
import { PluginExtensionLink, PluginExtensionPoints } from '@grafana/data';
import { usePluginLinks } from '@grafana/runtime';
import { CombinedRule, Rule, RuleGroupIdentifierV2 } from 'app/types/unified-alerting';
import { PromRuleType } from 'app/types/unified-alerting-dto';
import { getRulePluginOrigin } from '../utils/rules';
interface BaseRuleExtensionContext {
name: string;
namespace: string;
group: string;
expression: string;
labels: Record<string, string>;
}
export interface AlertingRuleExtensionContext extends BaseRuleExtensionContext {
annotations: Record<string, string>;
}
export interface RecordingRuleExtensionContext extends BaseRuleExtensionContext {}
export function useRulePluginLinkExtension(rule: Rule | undefined, groupIdentifier: RuleGroupIdentifierV2) {
// This ref provides a stable reference to an empty array, which is used to avoid re-renders when the rule is undefined.
const emptyResponse = useRef<PluginExtensionLink[]>([]);
const ruleExtensionPoint = useRuleExtensionPoint(rule, groupIdentifier);
const { links } = usePluginLinks(ruleExtensionPoint);
if (!rule) {
return emptyResponse.current;
}
const ruleOrigin = getRulePluginOrigin(rule);
const ruleType = rule.type;
if (!ruleOrigin || !ruleType) {
return emptyResponse.current;
}
const { pluginId } = ruleOrigin;
return links.filter((link) => link.pluginId === pluginId);
}
export interface PluginRuleExtensionParam {
pluginId: string;
rule: CombinedRule;
}
interface AlertingRuleExtensionPoint {
extensionPointId: PluginExtensionPoints.AlertingAlertingRuleAction;
context: AlertingRuleExtensionContext;
}
interface RecordingRuleExtensionPoint {
extensionPointId: PluginExtensionPoints.AlertingRecordingRuleAction;
context: RecordingRuleExtensionContext;
}
interface EmptyExtensionPoint {
extensionPointId: '';
}
type RuleExtensionPoint = AlertingRuleExtensionPoint | RecordingRuleExtensionPoint | EmptyExtensionPoint;
function useRuleExtensionPoint(rule: Rule | undefined, groupIdentifier: RuleGroupIdentifierV2): RuleExtensionPoint {
return useMemo<RuleExtensionPoint>(() => {
if (!rule) {
return { extensionPointId: '' };
}
const ruleType = rule.type;
const { namespace, groupName } = groupIdentifier;
const namespaceIdentifier = 'uid' in namespace ? namespace.uid : namespace.name;
switch (ruleType) {
case PromRuleType.Alerting:
return {
extensionPointId: PluginExtensionPoints.AlertingAlertingRuleAction,
context: {
name: rule.name,
namespace: namespaceIdentifier,
group: groupName,
expression: rule.query,
labels: rule.labels ?? {},
annotations: rule.annotations ?? {},
},
};
case PromRuleType.Recording:
return {
extensionPointId: PluginExtensionPoints.AlertingRecordingRuleAction,
context: {
name: rule.name,
namespace: namespaceIdentifier,
group: groupName,
expression: rule.query,
labels: rule.labels ?? {},
},
};
default:
return { extensionPointId: '' };
}
}, [groupIdentifier, rule]);
}