Alerting: Refactor and clean up rule type guard functions (#101639)
This commit is contained in:
@@ -25,7 +25,7 @@ import { ExportFormats } from '../components/export/providers';
|
||||
import { Folder } from '../types/rule-form';
|
||||
import { GRAFANA_RULES_SOURCE_NAME, getDatasourceAPIUid, isGrafanaRulesSource } from '../utils/datasource';
|
||||
import { arrayKeyValuesToObject } from '../utils/labels';
|
||||
import { isCloudRuleIdentifier, isGrafanaRulerRule, isPrometheusRuleIdentifier } from '../utils/rules';
|
||||
import { isCloudRuleIdentifier, isPrometheusRuleIdentifier, rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { WithNotificationOptions, alertingApi } from './alertingApi';
|
||||
import { GRAFANA_RULER_CONFIG } from './featureDiscoveryApi';
|
||||
@@ -330,7 +330,7 @@ export const alertRuleApi = alertingApi.injectEndpoints({
|
||||
};
|
||||
},
|
||||
invalidatesTags: (result, _error, { namespace, payload, rulerConfig }) => {
|
||||
const grafanaRulerRules = payload.rules.filter((rule) => isGrafanaRulerRule(rule));
|
||||
const grafanaRulerRules = payload.rules.filter(rulerRuleType.grafana.rule);
|
||||
|
||||
return [
|
||||
{ type: 'RuleNamespace', id: `${rulerConfig.dataSourceUid}/${namespace}` },
|
||||
|
||||
@@ -6,7 +6,7 @@ import { RulerGrafanaRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
import { usePauseRuleInGroup } from '../hooks/ruleGroup/usePauseAlertRule';
|
||||
import { isLoading } from '../hooks/useAsync';
|
||||
import { stringifyErrorLike } from '../utils/misc';
|
||||
import { isGrafanaRulerRulePaused } from '../utils/rules';
|
||||
import { isPausedRule } from '../utils/rules';
|
||||
|
||||
interface Props {
|
||||
rule: RulerGrafanaRuleDTO;
|
||||
@@ -25,7 +25,7 @@ const MenuItemPauseRule = ({ rule, groupIdentifier, onPauseChange }: Props) => {
|
||||
const notifyApp = useAppNotification();
|
||||
const [pauseRule, updateState] = usePauseRuleInGroup();
|
||||
|
||||
const [icon, title] = isGrafanaRulerRulePaused(rule)
|
||||
const [icon, title] = isPausedRule(rule)
|
||||
? ['play' as const, 'Resume evaluation']
|
||||
: ['pause' as const, 'Pause evaluation'];
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import { useRuleWithLocation } from '../../hooks/useCombinedRule';
|
||||
import { formValuesFromExistingRule } from '../../rule-editor/formDefaults';
|
||||
import { stringifyErrorLike } from '../../utils/misc';
|
||||
import * as ruleId from '../../utils/rule-id';
|
||||
import { isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { rulerRuleType } from '../../utils/rules';
|
||||
import { createRelativeUrl } from '../../utils/url';
|
||||
import { withPageErrorBoundary } from '../../withPageErrorBoundary';
|
||||
import { AlertingPageWrapper } from '../AlertingPageWrapper';
|
||||
@@ -58,7 +58,7 @@ function RuleModifyExport({ ruleIdentifier }: { ruleIdentifier: RuleIdentifier }
|
||||
);
|
||||
}
|
||||
|
||||
if (rulerRule && !isGrafanaRulerRule(rulerRule.rule)) {
|
||||
if (rulerRule && !rulerRuleType.grafana.rule(rulerRule.rule)) {
|
||||
// alert rule exists but is not a grafana-managed rule
|
||||
return (
|
||||
<Alert
|
||||
@@ -69,7 +69,7 @@ function RuleModifyExport({ ruleIdentifier }: { ruleIdentifier: RuleIdentifier }
|
||||
);
|
||||
}
|
||||
|
||||
if (rulerRule && isGrafanaRulerRule(rulerRule.rule)) {
|
||||
if (rulerRule && rulerRuleType.grafana.rule(rulerRule.rule)) {
|
||||
return (
|
||||
<ModifyExportRuleForm
|
||||
ruleForm={formValuesFromExistingRule(rulerRule)}
|
||||
|
||||
+4
-2
@@ -31,7 +31,7 @@ import {
|
||||
isGrafanaAlertingRuleByType,
|
||||
isGrafanaManagedRuleByType,
|
||||
isGrafanaRecordingRuleByType,
|
||||
isGrafanaRulerRule,
|
||||
rulerRuleType,
|
||||
} from '../../utils/rules';
|
||||
import { parsePrometheusDuration } from '../../utils/time';
|
||||
import { CollapseToggle } from '../CollapseToggle';
|
||||
@@ -82,7 +82,9 @@ const namespaceToGroupOptions = (rulerNamespace: RulerRulesConfigDTO, enableProv
|
||||
};
|
||||
|
||||
const isProvisionedGroup = (group: RulerRuleGroupDTO) => {
|
||||
return group.rules.some((rule) => isGrafanaRulerRule(rule) && Boolean(rule.grafana_alert.provenance) === true);
|
||||
return group.rules.some(
|
||||
(rule) => rulerRuleType.grafana.rule(rule) && Boolean(rule.grafana_alert.provenance) === true
|
||||
);
|
||||
};
|
||||
|
||||
const sortByLabel = (a: SelectableValue<string>, b: SelectableValue<string>) => {
|
||||
|
||||
@@ -14,7 +14,7 @@ import {
|
||||
formValuesToRulerRuleDTO,
|
||||
recordingRulerRuleToRuleForm,
|
||||
} from '../../utils/rule-form';
|
||||
import { isAlertingRulerRule, isRecordingRulerRule } from '../../utils/rules';
|
||||
import { rulerRuleType } from '../../utils/rules';
|
||||
|
||||
interface Props {
|
||||
onClose: () => void;
|
||||
@@ -145,9 +145,9 @@ function YamlContentInfo() {
|
||||
}
|
||||
|
||||
function rulerRuleToRuleFormValues(rulerRule: RulerRuleDTO): Partial<RuleFormValues> {
|
||||
if (isAlertingRulerRule(rulerRule)) {
|
||||
if (rulerRuleType.dataSource.alertingRule(rulerRule)) {
|
||||
return alertingRulerRuleToRuleForm(rulerRule);
|
||||
} else if (isRecordingRulerRule(rulerRule)) {
|
||||
} else if (rulerRuleType.dataSource.recordingRule(rulerRule)) {
|
||||
return recordingRulerRuleToRuleForm(rulerRule);
|
||||
}
|
||||
|
||||
|
||||
+6
-6
@@ -16,11 +16,10 @@ import {
|
||||
getRuleGroupLocationFromRuleWithLocation,
|
||||
isCloudAlertingRuleByType,
|
||||
isCloudRecordingRuleByType,
|
||||
isCloudRulerRule,
|
||||
isGrafanaManagedRuleByType,
|
||||
isGrafanaRulerRule,
|
||||
isGrafanaRulerRulePaused,
|
||||
isPausedRule,
|
||||
isRecordingRuleByType,
|
||||
rulerRuleType,
|
||||
} from 'app/features/alerting/unified/utils/rules';
|
||||
import { isExpressionQuery } from 'app/features/expressions/guards';
|
||||
import { RuleGroupIdentifier, RuleIdentifier, RuleWithLocation } from 'app/types/unified-alerting';
|
||||
@@ -209,7 +208,7 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
|
||||
|
||||
// Cloud Ruler rules identifier changes on update due to containing rule name and hash components
|
||||
// After successful update we need to update the URL to avoid displaying 404 errors
|
||||
if (isCloudRulerRule(ruleDefinition)) {
|
||||
if (rulerRuleType.dataSource.rule(ruleDefinition)) {
|
||||
const updatedRuleIdentifier = fromRulerRule(dataSourceName, namespaceName, groupName, ruleDefinition);
|
||||
locationService.replace(`/alerting/${encodeURIComponent(stringifyIdentifier(updatedRuleIdentifier))}/edit`);
|
||||
}
|
||||
@@ -295,7 +294,8 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
|
||||
</Stack>
|
||||
);
|
||||
|
||||
const isPaused = existing && isGrafanaRulerRule(existing.rule) && isGrafanaRulerRulePaused(existing.rule);
|
||||
const isPaused = rulerRuleType.grafana.alertingRule(existing?.rule) && isPausedRule(existing?.rule);
|
||||
|
||||
if (!type) {
|
||||
return null;
|
||||
}
|
||||
@@ -369,7 +369,7 @@ export const AlertRuleForm = ({ existing, prefill, isManualRestore }: Props) =>
|
||||
function getReturnToUrl(groupId: RuleGroupIdentifier, rule: RulerRuleDTO | PostableRuleGrafanaRuleDTO) {
|
||||
const { dataSourceName, namespaceName, groupName } = groupId;
|
||||
|
||||
if (prometheusRulesPrimary && isCloudRulerRule(rule)) {
|
||||
if (prometheusRulesPrimary && rulerRuleType.dataSource.rule(rule)) {
|
||||
const ruleIdentifier = fromRulerRule(dataSourceName, namespaceName, groupName, rule);
|
||||
return createViewLinkFromIdentifier(ruleIdentifier);
|
||||
}
|
||||
|
||||
+2
-2
@@ -20,7 +20,7 @@ import { DEFAULT_GROUP_EVALUATION_INTERVAL, getDefaultFormValues } from '../../.
|
||||
import { RuleFormType, RuleFormValues } from '../../../types/rule-form';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../../utils/datasource';
|
||||
import { formValuesToRulerGrafanaRuleDTO, getDefaultQueries } from '../../../utils/rule-form';
|
||||
import { isGrafanaRulerRule } from '../../../utils/rules';
|
||||
import { rulerRuleType } from '../../../utils/rules';
|
||||
import { FileExportPreview } from '../../export/FileExportPreview';
|
||||
import { GrafanaExportDrawer } from '../../export/GrafanaExportDrawer';
|
||||
import { ExportFormats, HclExportProvider, allGrafanaExportProviders } from '../../export/providers';
|
||||
@@ -150,7 +150,7 @@ export const getPayloadToExport = (
|
||||
// we have to update the rule in the group in the same position if it exists, otherwise we have to add it at the end
|
||||
let alreadyExistsInGroup = false;
|
||||
const updatedRules = existingGroup.rules.map((rule: RulerRuleDTO) => {
|
||||
if (isGrafanaRulerRule(rule) && rule.grafana_alert.uid === ruleUid) {
|
||||
if (rulerRuleType.grafana.rule(rule) && rule.grafana_alert.uid === ruleUid) {
|
||||
alreadyExistsInGroup = true;
|
||||
return updatedRule;
|
||||
} else {
|
||||
|
||||
@@ -10,7 +10,7 @@ import { PromAlertingRuleState, RulerRuleDTO } from 'app/types/unified-alerting-
|
||||
import { AlertRuleAction, useRulerRuleAbility } from '../../hooks/useAbilities';
|
||||
import { createShareLink, isLocalDevEnv, isOpenSourceEdition } from '../../utils/misc';
|
||||
import * as ruleId from '../../utils/rule-id';
|
||||
import { isAlertingRule, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { prometheusRuleType, rulerRuleType } from '../../utils/rules';
|
||||
import { createRelativeUrl } from '../../utils/url';
|
||||
import { DeclareIncidentMenuItem } from '../bridges/DeclareIncidentButton';
|
||||
|
||||
@@ -76,7 +76,7 @@ const AlertRuleMenu = ({
|
||||
// @TODO Migrate "declare incident button" to plugin links extensions
|
||||
const shouldShowDeclareIncidentButton =
|
||||
(!isOpenSourceEdition() || isLocalDevEnv()) &&
|
||||
isAlertingRule(promRule) &&
|
||||
prometheusRuleType.alertingRule(promRule) &&
|
||||
promRule.state === PromAlertingRuleState.Firing;
|
||||
|
||||
const shareUrl = createShareLink(identifier);
|
||||
@@ -86,7 +86,7 @@ const AlertRuleMenu = ({
|
||||
|
||||
const menuItems = (
|
||||
<>
|
||||
{canPause && isGrafanaRulerRule(rulerRule) && groupIdentifier.groupOrigin === 'grafana' && (
|
||||
{canPause && rulerRuleType.grafana.rule(rulerRule) && groupIdentifier.groupOrigin === 'grafana' && (
|
||||
<MenuItemPauseRule rule={rulerRule} groupIdentifier={groupIdentifier} onPauseChange={onPauseChange} />
|
||||
)}
|
||||
{canSilence && <Menu.Item label="Silence notifications" icon="bell-slash" onClick={handleSilence} />}
|
||||
|
||||
@@ -343,21 +343,30 @@ describe('RuleViewer', () => {
|
||||
const mockRule = getVanillaPromRule({
|
||||
name: 'prom test alert',
|
||||
namespace: mockCombinedCloudRuleNamespace({ name: 'prometheus' }, prometheus.name),
|
||||
annotations: { [Annotation.summary]: 'prom summary', [Annotation.runbookURL]: 'https://runbook.example.com' },
|
||||
annotations: {
|
||||
[Annotation.summary]: 'prom summary',
|
||||
[Annotation.runbookURL]: 'https://runbook.example.com',
|
||||
},
|
||||
promRule: {
|
||||
...mockPromAlertingRule(),
|
||||
...mockPromAlertingRule({
|
||||
annotations: {
|
||||
[Annotation.summary]: 'prom summary',
|
||||
[Annotation.runbookURL]: 'https://runbook.example.com',
|
||||
},
|
||||
}),
|
||||
duration: 900, // 15 minutes
|
||||
},
|
||||
});
|
||||
|
||||
const mockRuleIdentifier = ruleId.fromCombinedRule(prometheus.name, mockRule);
|
||||
|
||||
it('should render pending period for vanilla Prometheus alert rule', async () => {
|
||||
it('should render metadata for vanilla Prometheus alert rule', async () => {
|
||||
renderRuleViewer(mockRule, mockRuleIdentifier, ActiveTab.Details);
|
||||
|
||||
expect(screen.getByText('prom test alert')).toBeInTheDocument();
|
||||
|
||||
// One summary is rendered by the Title component, and the other by the DetailsTab component
|
||||
// Both summary and runbook are rendered by the Title component, and the DetailsTab component
|
||||
expect(ELEMENTS.metadata.summary(mockRule.annotations[Annotation.runbookURL]).getAll()).toHaveLength(2);
|
||||
expect(ELEMENTS.metadata.summary(mockRule.annotations[Annotation.summary]).getAll()).toHaveLength(2);
|
||||
|
||||
expect(ELEMENTS.details.pendingPeriod.get()).toHaveTextContent(/15m/i);
|
||||
|
||||
@@ -23,12 +23,10 @@ import { makeDashboardLink, makePanelLink, stringifyErrorLike } from '../../util
|
||||
import {
|
||||
RulePluginOrigin,
|
||||
getRulePluginOrigin,
|
||||
isAlertingRule,
|
||||
isFederatedRuleGroup,
|
||||
isGrafanaRecordingRule,
|
||||
isGrafanaRulerRule,
|
||||
isGrafanaRulerRulePaused,
|
||||
isRecordingRule,
|
||||
isPausedRule,
|
||||
prometheusRuleType,
|
||||
rulerRuleType,
|
||||
} from '../../utils/rules';
|
||||
import { createRelativeUrl } from '../../utils/url';
|
||||
import { AlertLabels } from '../AlertLabels';
|
||||
@@ -71,11 +69,11 @@ const RuleViewer = () => {
|
||||
const { annotations, promRule, rulerRule } = rule;
|
||||
|
||||
const hasError = isErrorHealth(promRule?.health);
|
||||
const isAlertType = isAlertingRule(promRule);
|
||||
const isAlertType = prometheusRuleType.alertingRule(promRule);
|
||||
|
||||
const isFederatedRule = isFederatedRuleGroup(rule.group);
|
||||
const isProvisioned = isGrafanaRulerRule(rulerRule) && Boolean(rulerRule.grafana_alert.provenance);
|
||||
const isPaused = isGrafanaRulerRule(rulerRule) && isGrafanaRulerRulePaused(rulerRule);
|
||||
const isProvisioned = rulerRuleType.grafana.rule(rulerRule) && Boolean(rulerRule.grafana_alert.provenance);
|
||||
const isPaused = rulerRuleType.grafana.alertingRule(rulerRule) && isPausedRule(rulerRule);
|
||||
|
||||
const showError = hasError && !isPaused;
|
||||
const ruleOrigin = rulerRule ? getRulePluginOrigin(rulerRule) : getRulePluginOrigin(promRule);
|
||||
@@ -126,10 +124,12 @@ const RuleViewer = () => {
|
||||
<TabContent>
|
||||
{activeTab === ActiveTab.Query && <QueryResults rule={rule} />}
|
||||
{activeTab === ActiveTab.Instances && <InstancesList rule={rule} />}
|
||||
{activeTab === ActiveTab.History && isGrafanaRulerRule(rule.rulerRule) && <History rule={rule.rulerRule} />}
|
||||
{activeTab === ActiveTab.History && rulerRuleType.grafana.rule(rule.rulerRule) && (
|
||||
<History rule={rule.rulerRule} />
|
||||
)}
|
||||
{activeTab === ActiveTab.Routing && <Routing />}
|
||||
{activeTab === ActiveTab.Details && <Details rule={rule} />}
|
||||
{activeTab === ActiveTab.VersionHistory && isGrafanaRulerRule(rule.rulerRule) && (
|
||||
{activeTab === ActiveTab.VersionHistory && rulerRuleType.grafana.rule(rule.rulerRule) && (
|
||||
<AlertVersionHistory rule={rule.rulerRule} />
|
||||
)}
|
||||
</TabContent>
|
||||
@@ -206,7 +206,7 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
|
||||
),
|
||||
});
|
||||
}
|
||||
if (isGrafanaRecordingRule(rule.rulerRule)) {
|
||||
if (rulerRuleType.grafana.recordingRule(rule.rulerRule)) {
|
||||
const metric = rule.rulerRule?.grafana_alert.record?.metric ?? '';
|
||||
metadata.push({
|
||||
label: 'Metric name',
|
||||
@@ -336,15 +336,15 @@ function usePageNav(rule: CombinedRule) {
|
||||
const { annotations, promRule, rulerRule } = rule;
|
||||
|
||||
const summary = annotations[Annotation.summary];
|
||||
const isAlertType = isAlertingRule(promRule);
|
||||
const isAlertType = prometheusRuleType.alertingRule(promRule);
|
||||
const numberOfInstance = isAlertType ? calculateTotalInstances(rule.instanceTotals) : undefined;
|
||||
|
||||
const namespaceName = decodeGrafanaNamespace(rule.namespace).name;
|
||||
const groupName = rule.group.name;
|
||||
|
||||
const isGrafanaAlertRule = isGrafanaRulerRule(rulerRule) && isAlertType;
|
||||
const grafanaRecordingRule = isGrafanaRecordingRule(rulerRule);
|
||||
const isRecordingRuleType = isRecordingRule(promRule);
|
||||
const isGrafanaAlertRule = rulerRuleType.grafana.rule(rulerRule) && isAlertType;
|
||||
const grafanaRecordingRule = rulerRuleType.grafana.recordingRule(rulerRule);
|
||||
const isRecordingRuleType = prometheusRuleType.recordingRule(promRule);
|
||||
|
||||
const pageNav: NavModelItem = {
|
||||
...defaultPageNav,
|
||||
|
||||
@@ -7,13 +7,7 @@ import { Trans, t } from 'app/core/internationalization';
|
||||
import { CombinedRule } from 'app/types/unified-alerting';
|
||||
|
||||
import { usePendingPeriod } from '../../../hooks/rules/usePendingPeriod';
|
||||
import {
|
||||
getAnnotations,
|
||||
isGrafanaAlertingRule,
|
||||
isGrafanaRecordingRule,
|
||||
isGrafanaRulerRule,
|
||||
isRecordingRulerRule,
|
||||
} from '../../../utils/rules';
|
||||
import { getAnnotations, isPausedRule, prometheusRuleType, rulerRuleType } from '../../../utils/rules';
|
||||
import { isNullDate } from '../../../utils/time';
|
||||
import { Tokenize } from '../../Tokenize';
|
||||
import { DetailText } from '../../common/DetailText';
|
||||
@@ -25,6 +19,7 @@ enum RuleType {
|
||||
GrafanaManagedRecordingRule = 'Grafana-managed recording rule',
|
||||
CloudAlertRule = 'Cloud alert rule',
|
||||
CloudRecordingRule = 'Cloud recording rule',
|
||||
Unknown = 'Unknown',
|
||||
}
|
||||
|
||||
const DetailGroup = ({ title, children }: { title: string; children: React.ReactNode }) => {
|
||||
@@ -45,30 +40,29 @@ interface DetailsProps {
|
||||
export const Details = ({ rule }: DetailsProps) => {
|
||||
const styles = useStyles2(getStyles);
|
||||
|
||||
let ruleType: RuleType;
|
||||
|
||||
const pendingPeriod = usePendingPeriod(rule);
|
||||
|
||||
if (isGrafanaRulerRule(rule.rulerRule)) {
|
||||
ruleType = isGrafanaRecordingRule(rule.rulerRule)
|
||||
? RuleType.GrafanaManagedRecordingRule
|
||||
: RuleType.GrafanaManagedAlertRule;
|
||||
} else if (isRecordingRulerRule(rule.rulerRule)) {
|
||||
ruleType = RuleType.CloudRecordingRule;
|
||||
} else {
|
||||
// probably not the greatest assumption
|
||||
ruleType = RuleType.CloudAlertRule;
|
||||
let determinedRuleType: RuleType = RuleType.Unknown;
|
||||
if (rulerRuleType.grafana.alertingRule(rule.rulerRule)) {
|
||||
determinedRuleType = RuleType.GrafanaManagedAlertRule;
|
||||
} else if (rulerRuleType.grafana.recordingRule(rule.rulerRule)) {
|
||||
determinedRuleType = RuleType.GrafanaManagedRecordingRule;
|
||||
} else if (rulerRuleType.dataSource.alertingRule(rule.rulerRule)) {
|
||||
determinedRuleType = RuleType.CloudAlertRule;
|
||||
} else if (rulerRuleType.dataSource.recordingRule(rule.rulerRule)) {
|
||||
determinedRuleType = RuleType.CloudRecordingRule;
|
||||
}
|
||||
|
||||
const evaluationDuration = rule.promRule?.evaluationTime;
|
||||
const evaluationTimestamp = rule.promRule?.lastEvaluation;
|
||||
|
||||
const annotations = getAnnotations(rule);
|
||||
const annotations = prometheusRuleType.alertingRule(rule.promRule) ? getAnnotations(rule.promRule) : undefined;
|
||||
|
||||
const hasEvaluationDuration = Number.isFinite(evaluationDuration);
|
||||
|
||||
const updated = isGrafanaRulerRule(rule.rulerRule) ? rule.rulerRule.grafana_alert.updated : undefined;
|
||||
const isPaused = isGrafanaAlertingRule(rule.rulerRule) && rule.rulerRule.grafana_alert.is_paused;
|
||||
const updated = rulerRuleType.grafana.rule(rule.rulerRule) ? rule.rulerRule.grafana_alert.updated : undefined;
|
||||
const isPaused = rulerRuleType.grafana.alertingRule(rule.rulerRule) && isPausedRule(rule.rulerRule);
|
||||
|
||||
const pausedIcon = (
|
||||
<Stack>
|
||||
<Text color="warning">
|
||||
@@ -82,8 +76,8 @@ export const Details = ({ rule }: DetailsProps) => {
|
||||
return (
|
||||
<div className={styles.metadata}>
|
||||
<DetailGroup title={t('alerting.alert.rule', 'Rule')}>
|
||||
<DetailText id="rule-type" label={t('alerting.alert.rule-type', 'Rule type')} value={ruleType} />
|
||||
{isGrafanaRulerRule(rule.rulerRule) && (
|
||||
<DetailText id="rule-type" label={t('alerting.alert.rule-type', 'Rule type')} value={determinedRuleType} />
|
||||
{rulerRuleType.grafana.rule(rule.rulerRule) && (
|
||||
<>
|
||||
<DetailText
|
||||
id="rule-type"
|
||||
@@ -145,7 +139,7 @@ export const Details = ({ rule }: DetailsProps) => {
|
||||
)}
|
||||
</DetailGroup>
|
||||
|
||||
{isGrafanaRulerRule(rule.rulerRule) &&
|
||||
{rulerRuleType.grafana.rule(rule.rulerRule) &&
|
||||
// grafana recording rules don't have these fields
|
||||
rule.rulerRule.grafana_alert.no_data_state &&
|
||||
rule.rulerRule.grafana_alert.exec_err_state && (
|
||||
|
||||
@@ -8,7 +8,7 @@ import { CombinedRule } from 'app/types/unified-alerting';
|
||||
import { GrafanaRuleQueryViewer, QueryPreview } from '../../../GrafanaRuleQueryViewer';
|
||||
import { useAlertQueriesStatus } from '../../../hooks/useAlertQueriesStatus';
|
||||
import { alertRuleToQueries } from '../../../utils/query';
|
||||
import { isFederatedRuleGroup, isGrafanaRulerRule } from '../../../utils/rules';
|
||||
import { isFederatedRuleGroup, rulerRuleType } from '../../../utils/rules';
|
||||
import { useAlertQueryRunner } from '../../rule-editor/query-and-alert-condition/useAlertQueryRunner';
|
||||
|
||||
interface Props {
|
||||
@@ -25,7 +25,7 @@ const QueryResults = ({ rule }: Props) => {
|
||||
const onRunQueries = useCallback(() => {
|
||||
if (queries.length > 0 && allDataSourcesAvailable) {
|
||||
let condition;
|
||||
if (rule && isGrafanaRulerRule(rule.rulerRule)) {
|
||||
if (rule && rulerRuleType.grafana.rule(rule.rulerRule)) {
|
||||
condition = rule.rulerRule.grafana_alert.condition;
|
||||
}
|
||||
runQueries(queries, condition ?? 'A');
|
||||
@@ -46,7 +46,7 @@ const QueryResults = ({ rule }: Props) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
{isGrafanaRulerRule(rule.rulerRule) && !isFederatedRule && (
|
||||
{rulerRuleType.grafana.rule(rule.rulerRule) && !isFederatedRule && (
|
||||
<GrafanaRuleQueryViewer
|
||||
rule={rule}
|
||||
condition={rule.rulerRule.grafana_alert.condition}
|
||||
@@ -55,7 +55,7 @@ const QueryResults = ({ rule }: Props) => {
|
||||
/>
|
||||
)}
|
||||
|
||||
{!isGrafanaRulerRule(rule.rulerRule) &&
|
||||
{!rulerRuleType.grafana.rule(rule.rulerRule) &&
|
||||
!isFederatedRule &&
|
||||
queryPreviewData &&
|
||||
Object.keys(queryPreviewData).length > 0 && (
|
||||
|
||||
@@ -35,7 +35,7 @@ import { fetchRulerRulesAction, rulesInSameGroupHaveInvalidFor } from '../../sta
|
||||
import { checkEvaluationIntervalGlobalLimit } from '../../utils/config';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
|
||||
import { stringifyErrorLike } from '../../utils/misc';
|
||||
import { AlertInfo, getAlertInfo, isGrafanaOrDataSourceRecordingRule } from '../../utils/rules';
|
||||
import { AlertInfo, getAlertInfo, rulerRuleType } from '../../utils/rules';
|
||||
import { formatPrometheusDuration, parsePrometheusDuration, safeParsePrometheusDuration } from '../../utils/time';
|
||||
import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable';
|
||||
import { EvaluationIntervalLimitExceeded } from '../InvalidIntervalWarning';
|
||||
@@ -310,9 +310,7 @@ export function EditRuleGroupModalForm(props: ModalFormProps): React.ReactElemen
|
||||
notifyApp.error('There are errors in the form. Correct the errors and retry.');
|
||||
};
|
||||
|
||||
const rulesWithoutRecordingRules = compact(
|
||||
ruleGroup?.rules.filter((rule) => !isGrafanaOrDataSourceRecordingRule(rule))
|
||||
);
|
||||
const rulesWithoutRecordingRules = compact(ruleGroup?.rules.filter((rule) => !rulerRuleType.any.recordingRule(rule)));
|
||||
const hasSomeNoRecordingRules = rulesWithoutRecordingRules.length > 0;
|
||||
|
||||
return (
|
||||
|
||||
@@ -10,7 +10,6 @@ import {
|
||||
import cx from 'classnames';
|
||||
import { produce } from 'immer';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { Badge, Button, Icon, Modal, Tooltip, useStyles2 } from '@grafana/ui';
|
||||
@@ -31,12 +30,7 @@ import { SwapOperation, swapItems } from '../../reducers/ruler/ruleGroups';
|
||||
import { fetchRulerRulesAction } from '../../state/actions';
|
||||
import { isCloudRulesSource } from '../../utils/datasource';
|
||||
import { hashRulerRule } from '../../utils/rule-id';
|
||||
import {
|
||||
isAlertingRulerRule,
|
||||
isGrafanaRulerRule,
|
||||
isRecordingRulerRule,
|
||||
rulesSourceToDataSourceName,
|
||||
} from '../../utils/rules';
|
||||
import { getRuleName, rulerRuleType, rulesSourceToDataSourceName } from '../../utils/rules';
|
||||
|
||||
interface ModalProps {
|
||||
namespace: CombinedRuleNamespace;
|
||||
@@ -189,14 +183,16 @@ const ListItem = ({ provided, rule, isClone = false, isDragging = false }: ListI
|
||||
{...provided.draggableProps}
|
||||
{...provided.dragHandleProps}
|
||||
>
|
||||
{isGrafanaRulerRule(rule) && <div className={styles.listItemName}>{rule.grafana_alert.title}</div>}
|
||||
{isRecordingRulerRule(rule) && (
|
||||
<>
|
||||
<div className={styles.listItemName}>{rule.record}</div>
|
||||
<Badge text="Recording" color="purple" />
|
||||
</>
|
||||
)}
|
||||
{isAlertingRulerRule(rule) && <div className={styles.listItemName}>{rule.alert}</div>}
|
||||
<div className={styles.listItemName}>
|
||||
{getRuleName(rule)}
|
||||
{rulerRuleType.any.recordingRule(rule) && (
|
||||
<>
|
||||
{' '}
|
||||
<Badge text="Recording" color="purple" />
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
{rulerRuleType.dataSource.alertingRule(rule) && <div className={styles.listItemName}>{rule.alert}</div>}
|
||||
<Icon name="draggabledots" />
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -16,7 +16,7 @@ import { GRAFANA_RULES_SOURCE_NAME, getRulesSourceName } from '../../utils/datas
|
||||
import { groupIdentifier } from '../../utils/groupIdentifier';
|
||||
import { createViewLink } from '../../utils/misc';
|
||||
import * as ruleId from '../../utils/rule-id';
|
||||
import { isGrafanaAlertingRule, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { rulerRuleType } from '../../utils/rules';
|
||||
import { createRelativeUrl } from '../../utils/url';
|
||||
|
||||
import { RedirectToCloneRule } from './CloneRule';
|
||||
@@ -52,7 +52,7 @@ export const RuleActionsButtons = ({ compact, showViewButton, rule, rulesSource
|
||||
const { namespace, group, rulerRule } = rule;
|
||||
const { hasActiveFilters } = useRulesFilter();
|
||||
|
||||
const isProvisioned = isGrafanaRulerRule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance);
|
||||
const isProvisioned = rulerRuleType.grafana.rule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance);
|
||||
|
||||
const [editRuleSupported, editRuleAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Update);
|
||||
|
||||
@@ -125,7 +125,7 @@ export const RuleActionsButtons = ({ compact, showViewButton, rule, rulesSource
|
||||
buttonSize={buttonSize}
|
||||
/>
|
||||
{deleteModal}
|
||||
{isGrafanaAlertingRule(rule.rulerRule) && showSilenceDrawer && (
|
||||
{rulerRuleType.grafana.alertingRule(rule.rulerRule) && showSilenceDrawer && (
|
||||
<SilenceGrafanaRuleDrawer rulerRule={rule.rulerRule} onClose={() => setShowSilenceDrawer(false)} />
|
||||
)}
|
||||
{redirectToClone?.identifier && (
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Icon, Tooltip, useStyles2 } from '@grafana/ui/src';
|
||||
|
||||
import { CombinedRule } from '../../../../../types/unified-alerting';
|
||||
import { checkEvaluationIntervalGlobalLimit } from '../../utils/config';
|
||||
import { isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { rulerRuleType } from '../../utils/rules';
|
||||
|
||||
interface RuleConfigStatusProps {
|
||||
rule: CombinedRule;
|
||||
@@ -15,7 +15,7 @@ interface RuleConfigStatusProps {
|
||||
|
||||
export function RuleConfigStatus({ rule }: RuleConfigStatusProps) {
|
||||
const styles = useStyles2(getStyles);
|
||||
const isGrafanaManagedRule = isGrafanaRulerRule(rule.rulerRule);
|
||||
const isGrafanaManagedRule = rulerRuleType.grafana.rule(rule.rulerRule);
|
||||
|
||||
const exceedsLimit = useMemo(() => {
|
||||
return isGrafanaManagedRule ? checkEvaluationIntervalGlobalLimit(rule.group.interval).exceedsLimit : false;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { CombinedRule } from 'app/types/unified-alerting';
|
||||
|
||||
import { usePendingPeriod } from '../../hooks/rules/usePendingPeriod';
|
||||
import { useCleanAnnotations } from '../../utils/annotations';
|
||||
import { isGrafanaRecordingRule, isRecordingRule, isRecordingRulerRule } from '../../utils/rules';
|
||||
import { prometheusRuleType, rulerRuleType } from '../../utils/rules';
|
||||
import { isNullDate } from '../../utils/time';
|
||||
import { AlertLabels } from '../AlertLabels';
|
||||
import { DetailsField } from '../DetailsField';
|
||||
@@ -53,15 +53,12 @@ export const RuleDetails = ({ rule }: Props) => {
|
||||
<RuleDetailsDataSources rulesSource={rulesSource} rule={rule} />
|
||||
</div>
|
||||
</div>
|
||||
{!(
|
||||
isRecordingRulerRule(rule.rulerRule) ||
|
||||
isRecordingRule(rule.promRule) ||
|
||||
isGrafanaRecordingRule(rule.rulerRule)
|
||||
) && (
|
||||
<DetailsField label="Instances" horizontal={true}>
|
||||
<RuleDetailsMatchingInstances rule={rule} itemsDisplayLimit={INSTANCES_DISPLAY_LIMIT} />
|
||||
</DetailsField>
|
||||
)}
|
||||
{rulerRuleType.any.alertingRule(rule.rulerRule) ||
|
||||
(prometheusRuleType.alertingRule(rule.promRule) && (
|
||||
<DetailsField label="Instances" horizontal={true}>
|
||||
<RuleDetailsMatchingInstances rule={rule} itemsDisplayLimit={INSTANCES_DISPLAY_LIMIT} />
|
||||
</DetailsField>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -74,7 +71,9 @@ const EvaluationBehaviorSummary = ({ rule }: EvaluationBehaviorSummaryProps) =>
|
||||
const every = rule.group.interval;
|
||||
const lastEvaluation = rule.promRule?.lastEvaluation;
|
||||
const lastEvaluationDuration = rule.promRule?.evaluationTime;
|
||||
const metric = isGrafanaRecordingRule(rule.rulerRule) ? rule.rulerRule?.grafana_alert.record?.metric : undefined;
|
||||
const metric = rulerRuleType.grafana.recordingRule(rule.rulerRule)
|
||||
? rule.rulerRule?.grafana_alert.record?.metric
|
||||
: undefined;
|
||||
|
||||
const pendingPeriod = usePendingPeriod(rule);
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useStateHistoryModal } from '../../hooks/useStateHistoryModal';
|
||||
import { Annotation } from '../../utils/constants';
|
||||
import { isCloudRulesSource } from '../../utils/datasource';
|
||||
import { createExploreLink } from '../../utils/misc';
|
||||
import { isFederatedRuleGroup, isGrafanaAlertingRule, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { isFederatedRuleGroup, rulerRuleType } from '../../utils/rules';
|
||||
|
||||
interface Props {
|
||||
rule: CombinedRule;
|
||||
@@ -103,13 +103,13 @@ const RuleDetailsButtons = ({ rule, rulesSource }: Props) => {
|
||||
}
|
||||
}
|
||||
|
||||
if (isGrafanaAlertingRule(rule.rulerRule)) {
|
||||
if (rulerRuleType.grafana.alertingRule(rule.rulerRule)) {
|
||||
buttons.push(
|
||||
<Fragment key="history">
|
||||
<Button
|
||||
size="sm"
|
||||
icon="history"
|
||||
onClick={() => isGrafanaRulerRule(rule.rulerRule) && showStateHistoryModal(rule.rulerRule)}
|
||||
onClick={() => rulerRuleType.grafana.rule(rule.rulerRule) && showStateHistoryModal(rule.rulerRule)}
|
||||
>
|
||||
Show state history
|
||||
</Button>
|
||||
|
||||
@@ -8,7 +8,7 @@ import { ExpressionDatasourceUID } from 'app/features/expressions/types';
|
||||
import { CombinedRule, RulesSource } from 'app/types/unified-alerting';
|
||||
|
||||
import { isCloudRulesSource } from '../../utils/datasource';
|
||||
import { isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { rulerRuleType } from '../../utils/rules';
|
||||
import { DetailsField } from '../DetailsField';
|
||||
|
||||
type Props = {
|
||||
@@ -25,7 +25,7 @@ export function RuleDetailsDataSources(props: Props): JSX.Element | null {
|
||||
return [{ name: rulesSource.name, icon: rulesSource.meta.info.logos.small }];
|
||||
}
|
||||
|
||||
if (isGrafanaRulerRule(rule.rulerRule)) {
|
||||
if (rulerRuleType.grafana.rule(rule.rulerRule)) {
|
||||
const { data } = rule.rulerRule.grafana_alert;
|
||||
const unique = data.reduce<Record<string, { name: string; icon?: string }>>((dataSources, query) => {
|
||||
const ds = getDataSourceSrv().getInstanceSettings(query.datasourceUid);
|
||||
|
||||
+4
-4
@@ -1,7 +1,7 @@
|
||||
import { css, cx } from '@emotion/css';
|
||||
import { countBy, sum } from 'lodash';
|
||||
import { useMemo, useState } from 'react';
|
||||
import * as React from 'react';
|
||||
import { useMemo, useState } from 'react';
|
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data';
|
||||
import { LinkButton, useStyles2 } from '@grafana/ui';
|
||||
@@ -18,7 +18,7 @@ import { mapStateWithReasonToBaseState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { GRAFANA_RULES_SOURCE_NAME, isGrafanaRulesSource } from '../../utils/datasource';
|
||||
import { parsePromQLStyleMatcherLooseSafe } from '../../utils/matchers';
|
||||
import { isAlertingRule } from '../../utils/rules';
|
||||
import { prometheusRuleType } from '../../utils/rules';
|
||||
|
||||
import { AlertInstancesTable } from './AlertInstancesTable';
|
||||
import { getComponentsFromStats } from './RuleStats';
|
||||
@@ -73,13 +73,13 @@ export function RuleDetailsMatchingInstances(props: Props) {
|
||||
|
||||
const alerts = useMemo(
|
||||
(): Alert[] =>
|
||||
isAlertingRule(promRule) && promRule.alerts?.length
|
||||
prometheusRuleType.alertingRule(promRule) && promRule.alerts?.length
|
||||
? filterAlerts(queryString, alertState, sortAlerts(SortOrder.Importance, promRule.alerts))
|
||||
: [],
|
||||
[promRule, alertState, queryString]
|
||||
);
|
||||
|
||||
if (!isAlertingRule(promRule)) {
|
||||
if (!prometheusRuleType.alertingRule(promRule)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ import { GRAFANA_RULES_SOURCE_NAME, getRulesDataSources } from '../../utils/data
|
||||
import { createViewLink } from '../../utils/misc';
|
||||
import { isAsyncRequestStatePending } from '../../utils/redux';
|
||||
import { hashRule } from '../../utils/rule-id';
|
||||
import { getRulePluginOrigin, isAlertingRule, isProvisionedRule } from '../../utils/rules';
|
||||
import { getRulePluginOrigin, isProvisionedRule, prometheusRuleType } from '../../utils/rules';
|
||||
import { calculateTotalInstances } from '../rule-viewer/RuleViewer';
|
||||
|
||||
import { RuleActionsButtons } from './RuleActionsButtons';
|
||||
@@ -43,7 +43,7 @@ export const RuleListStateView = ({ namespaces }: Props) => {
|
||||
// We might hit edge cases where there type = alerting, but there is no state.
|
||||
// In this case, we shouldn't try to group these alerts in the state view
|
||||
// Even though we handle this at the API layer, this is a last catch point for any edge cases
|
||||
if (rule.promRule && isAlertingRule(rule.promRule) && rule.promRule.state) {
|
||||
if (prometheusRuleType.alertingRule(rule.promRule) && rule.promRule.state) {
|
||||
result.get(rule.promRule.state)?.push(rule);
|
||||
}
|
||||
})
|
||||
@@ -103,7 +103,9 @@ const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: C
|
||||
const { rulerRule, promRule } = rule;
|
||||
|
||||
const isProvisioned = rulerRule ? isProvisionedRule(rulerRule) : false;
|
||||
const instancesCount = isAlertingRule(rule.promRule) ? calculateTotalInstances(rule.instanceTotals) : undefined;
|
||||
const instancesCount = prometheusRuleType.alertingRule(rule.promRule)
|
||||
? calculateTotalInstances(rule.instanceTotals)
|
||||
: undefined;
|
||||
|
||||
if (!promRule) {
|
||||
return null;
|
||||
|
||||
@@ -7,7 +7,7 @@ import { Trans } from 'app/core/internationalization';
|
||||
import { CombinedRule } from 'app/types/unified-alerting';
|
||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { getFirstActiveAt, isAlertingRule, isGrafanaRecordingRule, isRecordingRule } from '../../utils/rules';
|
||||
import { getFirstActiveAt, prometheusRuleType, rulerRuleType } from '../../utils/rules';
|
||||
import { StateTag } from '../StateTag';
|
||||
|
||||
import { AlertStateTag } from './AlertStateTag';
|
||||
@@ -24,7 +24,7 @@ export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) =>
|
||||
const { promRule, rulerRule } = rule;
|
||||
// return how long the rule has been in its firing state, if any
|
||||
const RecordingRuleState = () => {
|
||||
if (isPaused && isGrafanaRecordingRule(rulerRule)) {
|
||||
if (isPaused && rulerRuleType.grafana.recordingRule(rulerRule)) {
|
||||
return (
|
||||
<Tooltip content={'Recording rule evaluation is currently paused'} placement="top">
|
||||
<StateTag state="warning">
|
||||
@@ -39,8 +39,7 @@ export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) =>
|
||||
};
|
||||
const forTime = useMemo(() => {
|
||||
if (
|
||||
promRule &&
|
||||
isAlertingRule(promRule) &&
|
||||
prometheusRuleType.alertingRule(promRule) &&
|
||||
promRule.alerts?.length &&
|
||||
promRule.state !== PromAlertingRuleState.Inactive
|
||||
) {
|
||||
@@ -80,14 +79,14 @@ export const RuleState = ({ rule, isDeleting, isCreating, isPaused }: Props) =>
|
||||
<Trans i18nKey="alerting.rule-state.creating">Creating</Trans>
|
||||
</Stack>
|
||||
);
|
||||
} else if (promRule && isAlertingRule(promRule)) {
|
||||
} else if (prometheusRuleType.alertingRule(promRule)) {
|
||||
return (
|
||||
<Stack gap={1}>
|
||||
<AlertStateTag state={promRule.state} isPaused={isPaused} />
|
||||
{!isPaused && forTime}
|
||||
</Stack>
|
||||
);
|
||||
} else if (promRule && isRecordingRule(promRule)) {
|
||||
} else if (promRule && prometheusRuleType.recordingRule(promRule)) {
|
||||
return <RecordingRuleState />;
|
||||
}
|
||||
return <>n/a</>;
|
||||
|
||||
@@ -15,7 +15,7 @@ import { useHasRuler } from '../../hooks/useHasRuler';
|
||||
import { useRulesAccess } from '../../utils/accessControlHooks';
|
||||
import { GRAFANA_RULES_SOURCE_NAME, getRulesSourceName, isCloudRulesSource } from '../../utils/datasource';
|
||||
import { makeFolderLink, makeFolderSettingsLink } from '../../utils/misc';
|
||||
import { isFederatedRuleGroup, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { isFederatedRuleGroup, rulerRuleType } from '../../utils/rules';
|
||||
import { CollapseToggle } from '../CollapseToggle';
|
||||
import { RuleLocation } from '../RuleLocation';
|
||||
import { GrafanaRuleFolderExporter } from '../export/GrafanaRuleFolderExporter';
|
||||
@@ -63,7 +63,8 @@ export const RulesGroup = React.memo(({ group, namespace, expandAll, viewMode }:
|
||||
const { currentData: dsFeatures } = useDiscoverDsFeaturesQuery({ rulesSourceName });
|
||||
|
||||
const rulerRule = group.rules[0]?.rulerRule;
|
||||
const folderUID = (rulerRule && isGrafanaRulerRule(rulerRule) && rulerRule.grafana_alert.namespace_uid) || undefined;
|
||||
const folderUID =
|
||||
(rulerRule && rulerRuleType.grafana.rule(rulerRule) && rulerRule.grafana_alert.namespace_uid) || undefined;
|
||||
const { folder } = useFolder(folderUID);
|
||||
|
||||
// group "is deleting" if rules source has ruler, but this group has no rules that are in ruler
|
||||
@@ -72,7 +73,7 @@ export const RulesGroup = React.memo(({ group, namespace, expandAll, viewMode }:
|
||||
|
||||
// check if group has provisioned items
|
||||
const isProvisioned = group.rules.some((rule) => {
|
||||
return isGrafanaRulerRule(rule.rulerRule) && rule.rulerRule.grafana_alert.provenance;
|
||||
return rulerRuleType.grafana.rule(rule.rulerRule) && rule.rulerRule.grafana_alert.provenance;
|
||||
});
|
||||
|
||||
// check what view mode we are in
|
||||
|
||||
@@ -19,7 +19,7 @@ import { PluginOriginBadge } from '../../plugins/PluginOriginBadge';
|
||||
import { calculateNextEvaluationEstimate } from '../../rule-list/components/util';
|
||||
import { Annotation } from '../../utils/constants';
|
||||
import { GRAFANA_RULES_SOURCE_NAME, getRulesSourceName } from '../../utils/datasource';
|
||||
import { getRulePluginOrigin, isGrafanaRulerRule, isGrafanaRulerRulePaused } from '../../utils/rules';
|
||||
import { getRulePluginOrigin, isPausedRule, rulerRuleType } from '../../utils/rules';
|
||||
import { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable';
|
||||
import { DynamicTableWithGuidelines } from '../DynamicTableWithGuidelines';
|
||||
import { ProvisioningBadge } from '../Provisioning';
|
||||
@@ -219,7 +219,7 @@ function useColumns(
|
||||
return <PluginOriginBadge pluginId={originMeta.pluginId} />;
|
||||
}
|
||||
|
||||
const isGrafanaManagedRule = isGrafanaRulerRule(rulerRule);
|
||||
const isGrafanaManagedRule = rulerRuleType.grafana.rule(rulerRule);
|
||||
if (!isGrafanaManagedRule) {
|
||||
return null;
|
||||
}
|
||||
@@ -347,13 +347,13 @@ function useRuleStatus(rule: CombinedRule) {
|
||||
|
||||
// If prometheusRulesPrimary is enabled, we don't fetch rules from the Ruler API (except for Grafana managed rules)
|
||||
// so there is no way to detect statuses
|
||||
if (prometheusRulesPrimary && !isGrafanaRulerRule(rulerRule)) {
|
||||
if (prometheusRulesPrimary && !rulerRuleType.grafana.rule(rulerRule)) {
|
||||
return { isDeleting: false, isCreating: false, isPaused: false };
|
||||
}
|
||||
|
||||
const isDeleting = Boolean(hasRuler && rulerRulesLoaded && promRule && !rulerRule);
|
||||
const isCreating = Boolean(hasRuler && rulerRulesLoaded && rulerRule && !promRule);
|
||||
const isPaused = isGrafanaRulerRule(rulerRule) && isGrafanaRulerRulePaused(rulerRule);
|
||||
const isPaused = rulerRuleType.grafana.alertingRule(rulerRule) && isPausedRule(rulerRule);
|
||||
|
||||
return { isDeleting, isCreating, isPaused };
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import { PostableRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { alertRuleApi } from '../../api/alertRuleApi';
|
||||
import { addRuleAction, updateRuleAction } from '../../reducers/ruler/ruleGroups';
|
||||
import { isGrafanaRuleIdentifier, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { isGrafanaRuleIdentifier, rulerRuleType } from '../../utils/rules';
|
||||
import { useAsync } from '../useAsync';
|
||||
|
||||
import { useDeleteRuleFromGroup } from './useDeleteRuleFromGroup';
|
||||
@@ -132,7 +132,7 @@ function copyGrafanaUID(ruleIdentifier: EditableRuleIdentifier, ruleDefinition:
|
||||
// by copying over the rule UID the backend will perform an atomic move operation
|
||||
// so there is no need for us to manually remove it from the previous group
|
||||
return produce(ruleDefinition, (draft) => {
|
||||
const isGrafanaManagedRuleDefinition = isGrafanaRulerRule(draft);
|
||||
const isGrafanaManagedRuleDefinition = rulerRuleType.grafana.rule(draft);
|
||||
|
||||
if (isGrafanaManagedRuleIdentifier && isGrafanaManagedRuleDefinition) {
|
||||
draft.grafana_alert.uid = ruleIdentifier.uid;
|
||||
|
||||
@@ -22,7 +22,7 @@ import { getInstancesPermissions, getNotificationsPermissions, getRulesPermissio
|
||||
import { getRulesSourceName } from '../utils/datasource';
|
||||
import { getGroupOriginName } from '../utils/groupIdentifier';
|
||||
import { isAdmin } from '../utils/misc';
|
||||
import { isFederatedRuleGroup, isGrafanaRecordingRule, isGrafanaRulerRule, isPluginProvidedRule } from '../utils/rules';
|
||||
import { isFederatedRuleGroup, isPluginProvidedRule, rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { useIsRuleEditable } from './useIsRuleEditable';
|
||||
|
||||
@@ -206,9 +206,10 @@ export function useAllAlertRuleAbilities(rule: CombinedRule): Abilities<AlertRul
|
||||
const canSilence = useCanSilence(rule.rulerRule);
|
||||
|
||||
const abilities = useMemo<Abilities<AlertRuleAction>>(() => {
|
||||
const isProvisioned = isGrafanaRulerRule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance);
|
||||
const isProvisioned =
|
||||
rulerRuleType.grafana.rule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance);
|
||||
const isFederated = isFederatedRuleGroup(rule.group);
|
||||
const isGrafanaManagedAlertRule = isGrafanaRulerRule(rule.rulerRule);
|
||||
const isGrafanaManagedAlertRule = rulerRuleType.grafana.rule(rule.rulerRule);
|
||||
const isPluginProvided = isPluginProvidedRule(rule.rulerRule);
|
||||
|
||||
// if a rule is either provisioned, federated or provided by a plugin rule, we don't allow it to be removed or edited
|
||||
@@ -252,10 +253,10 @@ export function useAllRulerRuleAbilities(
|
||||
const canSilence = useCanSilence(rule);
|
||||
|
||||
const abilities = useMemo<Abilities<AlertRuleAction>>(() => {
|
||||
const isProvisioned = isGrafanaRulerRule(rule) && Boolean(rule.grafana_alert.provenance);
|
||||
const isProvisioned = rulerRuleType.grafana.rule(rule) && Boolean(rule.grafana_alert.provenance);
|
||||
// const isFederated = isFederatedRuleGroup();
|
||||
const isFederated = false;
|
||||
const isGrafanaManagedAlertRule = isGrafanaRulerRule(rule);
|
||||
const isGrafanaManagedAlertRule = rulerRuleType.grafana.rule(rule);
|
||||
const isPluginProvided = isPluginProvidedRule(rule);
|
||||
|
||||
// if a rule is either provisioned, federated or provided by a plugin rule, we don't allow it to be removed or edited
|
||||
@@ -441,11 +442,11 @@ const { useGetGrafanaAlertingConfigurationStatusQuery } = alertmanagerApi;
|
||||
* 2. the admin has configured to only send instances to external AMs
|
||||
*/
|
||||
function useCanSilence(rule?: RulerRuleDTO): [boolean, boolean] {
|
||||
const folderUID = isGrafanaRulerRule(rule) ? rule.grafana_alert.namespace_uid : undefined;
|
||||
const folderUID = rulerRuleType.grafana.rule(rule) ? rule.grafana_alert.namespace_uid : undefined;
|
||||
const { loading: folderIsLoading, folder } = useFolder(folderUID);
|
||||
|
||||
const isGrafanaManagedRule = rule && isGrafanaRulerRule(rule);
|
||||
const isGrafanaRecording = rule && isGrafanaRecordingRule(rule);
|
||||
const isGrafanaManagedRule = rule && rulerRuleType.grafana.rule(rule);
|
||||
const isGrafanaRecording = rulerRuleType.grafana.recordingRule(rule);
|
||||
|
||||
const silenceSupported = useGrafanaRulesSilenceSupport();
|
||||
const canSilenceInFolder = useCanSilenceInFolder(folderUID);
|
||||
|
||||
@@ -32,13 +32,7 @@ import {
|
||||
isGrafanaRulesSource,
|
||||
} from '../utils/datasource';
|
||||
import { hashQuery } from '../utils/rule-id';
|
||||
import {
|
||||
isAlertingRule,
|
||||
isAlertingRulerRule,
|
||||
isGrafanaRulerRule,
|
||||
isRecordingRule,
|
||||
isRecordingRulerRule,
|
||||
} from '../utils/rules';
|
||||
import { getAnnotations, isPausedRule, prometheusRuleType, rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector';
|
||||
|
||||
@@ -98,7 +92,7 @@ export function useCombinedRuleNamespaces(
|
||||
|
||||
// We need to set the namespace_uid for grafana rules as it's required to obtain the rule's groups
|
||||
// All rules from all groups have the same namespace_uid so we're taking the first one.
|
||||
if (isGrafanaRulerRule(groups[0].rules[0])) {
|
||||
if (rulerRuleType.grafana.rule(groups[0].rules[0])) {
|
||||
namespace.uid = groups[0].rules[0].grafana_alert.namespace_uid;
|
||||
}
|
||||
|
||||
@@ -247,8 +241,10 @@ export function addRulerGroupsToCombinedNamespace(
|
||||
groups: RulerRuleGroupDTO[] = []
|
||||
): void {
|
||||
namespace.groups = groups.map((group) => {
|
||||
const numRecordingRules = group.rules.filter((rule) => isRecordingRulerRule(rule)).length;
|
||||
const numPaused = group.rules.filter((rule) => isGrafanaRulerRule(rule) && rule.grafana_alert.is_paused).length;
|
||||
const numRecordingRules = group.rules.filter((rule) => rulerRuleType.any.recordingRule(rule)).length;
|
||||
const numPaused = group.rules.filter((rule) => {
|
||||
return rulerRuleType.grafana.alertingRule(rule) && isPausedRule(rule);
|
||||
}).length;
|
||||
|
||||
const combinedGroup: CombinedRuleGroup = {
|
||||
name: group.name,
|
||||
@@ -298,8 +294,10 @@ export function addPromGroupsToCombinedNamespace(namespace: CombinedRuleNamespac
|
||||
const existingRule = getExistingRuleInGroup(rule, combinedRulesByName, namespace.rulesSource);
|
||||
if (existingRule) {
|
||||
existingRule.promRule = rule;
|
||||
existingRule.instanceTotals = isAlertingRule(rule) ? calculateRuleTotals(rule) : {};
|
||||
existingRule.filteredInstanceTotals = isAlertingRule(rule) ? calculateRuleFilteredTotals(rule) : {};
|
||||
existingRule.instanceTotals = prometheusRuleType.alertingRule(rule) ? calculateRuleTotals(rule) : {};
|
||||
existingRule.filteredInstanceTotals = prometheusRuleType.alertingRule(rule)
|
||||
? calculateRuleFilteredTotals(rule)
|
||||
: {};
|
||||
} else {
|
||||
combinedGroup!.rules.push(promRuleToCombinedRule(rule, namespace, combinedGroup!));
|
||||
}
|
||||
@@ -344,9 +342,9 @@ export function calculateGroupTotals(group: Pick<RuleGroup, 'rules' | 'totals'>)
|
||||
};
|
||||
}
|
||||
|
||||
const countsByState = countBy(group.rules, (rule) => isAlertingRule(rule) && rule.state);
|
||||
const countsByState = countBy(group.rules, (rule) => prometheusRuleType.alertingRule(rule) && rule.state);
|
||||
const countsByHealth = countBy(group.rules, (rule) => rule.health);
|
||||
const recordingCount = group.rules.filter((rule) => isRecordingRule(rule)).length;
|
||||
const recordingCount = group.rules.filter((rule) => prometheusRuleType.recordingRule(rule)).length;
|
||||
|
||||
return {
|
||||
alerting: countsByState[PromAlertingRuleState.Firing],
|
||||
@@ -382,12 +380,12 @@ function promRuleToCombinedRule(rule: Rule, namespace: CombinedRuleNamespace, gr
|
||||
name: rule.name,
|
||||
query: rule.query,
|
||||
labels: rule.labels || {},
|
||||
annotations: isAlertingRule(rule) ? rule.annotations || {} : {},
|
||||
annotations: prometheusRuleType.alertingRule(rule) ? getAnnotations(rule) : {},
|
||||
promRule: rule,
|
||||
namespace: namespace,
|
||||
group,
|
||||
instanceTotals: isAlertingRule(rule) ? calculateRuleTotals(rule) : {},
|
||||
filteredInstanceTotals: isAlertingRule(rule) ? calculateRuleFilteredTotals(rule) : {},
|
||||
instanceTotals: prometheusRuleType.alertingRule(rule) ? calculateRuleTotals(rule) : {},
|
||||
filteredInstanceTotals: prometheusRuleType.alertingRule(rule) ? calculateRuleFilteredTotals(rule) : {},
|
||||
};
|
||||
}
|
||||
|
||||
@@ -396,7 +394,7 @@ function rulerRuleToCombinedRule(
|
||||
namespace: CombinedRuleNamespace,
|
||||
group: CombinedRuleGroup
|
||||
): CombinedRule {
|
||||
return isAlertingRulerRule(rule)
|
||||
return rulerRuleType.dataSource.alertingRule(rule)
|
||||
? {
|
||||
name: rule.alert,
|
||||
query: rule.expr,
|
||||
@@ -408,7 +406,7 @@ function rulerRuleToCombinedRule(
|
||||
instanceTotals: {},
|
||||
filteredInstanceTotals: {},
|
||||
}
|
||||
: isRecordingRulerRule(rule)
|
||||
: rulerRuleType.dataSource.recordingRule(rule)
|
||||
? {
|
||||
name: rule.record,
|
||||
query: rule.expr,
|
||||
@@ -473,10 +471,18 @@ function getExistingRuleInGroup(
|
||||
}
|
||||
|
||||
function isCombinedRuleEqualToPromRule(combinedRule: CombinedRule, rule: Rule, checkQuery = true): boolean {
|
||||
const promRuleAnnotations = prometheusRuleType.alertingRule(rule) ? getAnnotations(rule) : {};
|
||||
const promRuleLabels = rule.labels ?? {};
|
||||
const promQuery = checkQuery ? hashQuery(rule.query) : '';
|
||||
|
||||
const combinedRuleAnnotations = combinedRule.annotations;
|
||||
const combinedRuleLabels = combinedRule.labels;
|
||||
const combinedRuleQuery = checkQuery ? hashQuery(combinedRule.query) : '';
|
||||
|
||||
if (combinedRule.name === rule.name) {
|
||||
return isEqual(
|
||||
[checkQuery ? hashQuery(combinedRule.query) : '', combinedRule.labels, combinedRule.annotations],
|
||||
[checkQuery ? hashQuery(rule.query) : '', rule.labels || {}, isAlertingRule(rule) ? rule.annotations || {} : {}]
|
||||
[combinedRuleQuery, combinedRuleLabels, combinedRuleAnnotations],
|
||||
[promQuery, promRuleLabels, promRuleAnnotations]
|
||||
);
|
||||
}
|
||||
return false;
|
||||
@@ -554,7 +560,7 @@ export function useCombinedRules(
|
||||
|
||||
// We need to set the namespace_uid for grafana rules as it's required to obtain the rule's groups
|
||||
// All rules from all groups have the same namespace_uid so we're taking the first one.
|
||||
if (isGrafanaRulerRule(groups[0].rules[0])) {
|
||||
if (rulerRuleType.grafana.rule(groups[0].rules[0])) {
|
||||
namespace.uid = groups[0].rules[0].grafana_alert.namespace_uid;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,13 +14,7 @@ import { labelsMatchMatchers, matcherToMatcherField } from '../utils/alertmanage
|
||||
import { Annotation } from '../utils/constants';
|
||||
import { isCloudRulesSource } from '../utils/datasource';
|
||||
import { parseMatcher, parsePromQLStyleMatcherLoose } from '../utils/matchers';
|
||||
import {
|
||||
getRuleHealth,
|
||||
isAlertingRule,
|
||||
isGrafanaRulerRule,
|
||||
isPluginProvidedRule,
|
||||
isPromRuleType,
|
||||
} from '../utils/rules';
|
||||
import { getRuleHealth, isPluginProvidedRule, isPromRuleType, prometheusRuleType, rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { calculateGroupTotals, calculateRuleFilteredTotals, calculateRuleTotals } from './useCombinedRuleNamespaces';
|
||||
import { useURLSearchParams } from './useURLSearchParams';
|
||||
@@ -106,7 +100,7 @@ export const useFilteredRules = (namespaces: CombinedRuleNamespace[], filterStat
|
||||
filteredRules.forEach((namespace) => {
|
||||
namespace.groups.forEach((group) => {
|
||||
group.rules.forEach((rule) => {
|
||||
if (isAlertingRule(rule.promRule)) {
|
||||
if (prometheusRuleType.alertingRule(rule.promRule)) {
|
||||
rule.instanceTotals = calculateRuleTotals(rule.promRule);
|
||||
rule.filteredInstanceTotals = calculateRuleFilteredTotals(rule.promRule);
|
||||
}
|
||||
@@ -225,7 +219,7 @@ const reduceGroups = (filterState: RulesFilter) => {
|
||||
if ('contactPoint' in matchesFilterFor) {
|
||||
const contactPoint = filterState.contactPoint;
|
||||
const hasContactPoint =
|
||||
isGrafanaRulerRule(rule.rulerRule) &&
|
||||
rulerRuleType.grafana.rule(rule.rulerRule) &&
|
||||
rule.rulerRule.grafana_alert.notification_settings?.receiver === contactPoint;
|
||||
|
||||
if (hasContactPoint) {
|
||||
@@ -234,7 +228,7 @@ const reduceGroups = (filterState: RulesFilter) => {
|
||||
}
|
||||
|
||||
if ('dataSourceNames' in matchesFilterFor) {
|
||||
if (isGrafanaRulerRule(rule.rulerRule)) {
|
||||
if (rulerRuleType.grafana.rule(rule.rulerRule)) {
|
||||
const doesNotQueryDs = isQueryingDataSource(rule.rulerRule, filterState);
|
||||
|
||||
if (doesNotQueryDs) {
|
||||
@@ -274,7 +268,7 @@ const reduceGroups = (filterState: RulesFilter) => {
|
||||
|
||||
if ('ruleState' in matchesFilterFor) {
|
||||
const promRule = rule.promRule;
|
||||
const hasPromRuleDefinition = promRule && isAlertingRule(promRule);
|
||||
const hasPromRuleDefinition = promRule && prometheusRuleType.alertingRule(promRule);
|
||||
|
||||
const ruleStateMatches = hasPromRuleDefinition && promRule.state === filterState.ruleState;
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ import { RulerRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { featureDiscoveryApi } from '../api/featureDiscoveryApi';
|
||||
import { getRulesPermissions } from '../utils/access-control';
|
||||
import { isGrafanaRulerRule } from '../utils/rules';
|
||||
import { rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { useFolder } from './useFolder';
|
||||
|
||||
@@ -24,7 +24,7 @@ export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO):
|
||||
rulesSourceName,
|
||||
});
|
||||
|
||||
const folderUID = rule && isGrafanaRulerRule(rule) ? rule.grafana_alert.namespace_uid : undefined;
|
||||
const folderUID = rule && rulerRuleType.grafana.rule(rule) ? rule.grafana_alert.namespace_uid : undefined;
|
||||
|
||||
const rulePermission = getRulesPermissions(rulesSourceName);
|
||||
const { folder, loading } = useFolder(folderUID);
|
||||
@@ -47,7 +47,7 @@ export function useIsRuleEditable(rulesSourceName: string, rule?: RulerRuleDTO):
|
||||
// Grafana rules can be edited if user can edit the folder they're in
|
||||
// When RBAC is disabled access to a folder is the only requirement for managing rules
|
||||
// When RBAC is enabled the appropriate alerting permissions need to be met
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
if (!folderUID) {
|
||||
throw new Error(
|
||||
`Rule ${rule.grafana_alert.title} does not have a folder uid, cannot determine if it is editable.`
|
||||
|
||||
@@ -6,12 +6,7 @@ import { PostableRuleDTO, PostableRulerRuleGroupDTO } from 'app/types/unified-al
|
||||
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../utils/datasource';
|
||||
import { hashRulerRule } from '../../utils/rule-id';
|
||||
import {
|
||||
isCloudRuleIdentifier,
|
||||
isCloudRulerRule,
|
||||
isGrafanaRuleIdentifier,
|
||||
isGrafanaRulerRule,
|
||||
} from '../../utils/rules';
|
||||
import { isCloudRuleIdentifier, isGrafanaRuleIdentifier, rulerRuleType } from '../../utils/rules';
|
||||
|
||||
// rule-scoped actions
|
||||
export const addRuleAction = createAction<{ rule: PostableRuleDTO; groupName?: string; interval?: string }>(
|
||||
@@ -61,7 +56,7 @@ export const ruleGroupReducer = createReducer(initialState, (builder) => {
|
||||
const index = findRuleIndex(draft.rules, identifier);
|
||||
const matchingRule = draft.rules[index];
|
||||
|
||||
if (isGrafanaRulerRule(matchingRule)) {
|
||||
if (rulerRuleType.grafana.rule(matchingRule)) {
|
||||
matchingRule.grafana_alert.is_paused = pause;
|
||||
} else {
|
||||
throw new Error('Matching rule is not a Grafana-managed rule');
|
||||
@@ -98,8 +93,8 @@ const ruleFinder = (identifier: RuleIdentifier) => {
|
||||
const dataSourceManagedIdentifier = isCloudRuleIdentifier(identifier);
|
||||
|
||||
return (rule: PostableRuleDTO) => {
|
||||
const isGrafanaManagedRule = isGrafanaRulerRule(rule);
|
||||
const isDataSourceManagedRule = isCloudRulerRule(rule);
|
||||
const isGrafanaManagedRule = rulerRuleType.grafana.rule(rule);
|
||||
const isDataSourceManagedRule = rulerRuleType.dataSource.rule(rule);
|
||||
|
||||
if (grafanaManagedIdentifier && isGrafanaManagedRule) {
|
||||
return rule.grafana_alert.uid === identifier.uid;
|
||||
|
||||
@@ -10,7 +10,7 @@ import { useRuleWithLocation } from '../hooks/useCombinedRule';
|
||||
import { generateCopiedName } from '../utils/duplicate';
|
||||
import { stringifyErrorLike } from '../utils/misc';
|
||||
import { rulerRuleToFormValues } from '../utils/rule-form';
|
||||
import { getRuleName, isAlertingRulerRule, isGrafanaRulerRule, isRecordingRulerRule } from '../utils/rules';
|
||||
import { getRuleName, rulerRuleType } from '../utils/rules';
|
||||
import { createRelativeUrl } from '../utils/url';
|
||||
|
||||
export function CloneRuleEditor({ sourceRuleId }: { sourceRuleId: RuleIdentifier }) {
|
||||
@@ -45,14 +45,14 @@ export function CloneRuleEditor({ sourceRuleId }: { sourceRuleId: RuleIdentifier
|
||||
}
|
||||
|
||||
function changeRuleName(rule: RulerRuleDTO, newName: string) {
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
rule.grafana_alert.title = newName;
|
||||
}
|
||||
if (isAlertingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.alertingRule(rule)) {
|
||||
rule.alert = newName;
|
||||
}
|
||||
|
||||
if (isRecordingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.recordingRule(rule)) {
|
||||
rule.record = newName;
|
||||
}
|
||||
}
|
||||
@@ -64,7 +64,7 @@ export function cloneRuleDefinition(rule: RuleWithLocation<RulerRuleDTO>) {
|
||||
generateCopiedName(getRuleName(ruleClone.rule), ruleClone.group.rules.map(getRuleName))
|
||||
);
|
||||
|
||||
if (isGrafanaRulerRule(ruleClone.rule)) {
|
||||
if (rulerRuleType.grafana.rule(ruleClone.rule)) {
|
||||
ruleClone.rule.grafana_alert.uid = '';
|
||||
|
||||
// Provisioned alert rules have provisioned alert group which cannot be used in UI
|
||||
|
||||
@@ -5,7 +5,7 @@ import { DataSourceRuleGroupIdentifier, Rule, RuleIdentifier } from 'app/types/u
|
||||
import { alertRuleApi } from '../api/alertRuleApi';
|
||||
import { featureDiscoveryApi } from '../api/featureDiscoveryApi';
|
||||
import { equal, fromRule, fromRulerRule, stringifyIdentifier } from '../utils/rule-id';
|
||||
import { getRulePluginOrigin, isAlertingRule, isRecordingRule } from '../utils/rules';
|
||||
import { getRulePluginOrigin, prometheusRuleType } from '../utils/rules';
|
||||
import { createRelativeUrl } from '../utils/url';
|
||||
|
||||
import { AlertRuleListItem, RecordingRuleListItem, UnknownRuleListItem } from './components/AlertRuleListItem';
|
||||
@@ -74,7 +74,7 @@ export const DataSourceRuleLoader = memo(function DataSourceRuleLoader({
|
||||
return null;
|
||||
}, [groupIdentifier, isLoading, rule, rulerRule]);
|
||||
|
||||
if (isAlertingRule(rule)) {
|
||||
if (prometheusRuleType.alertingRule(rule)) {
|
||||
return (
|
||||
<AlertRuleListItem
|
||||
name={rule.name}
|
||||
@@ -96,7 +96,7 @@ export const DataSourceRuleLoader = memo(function DataSourceRuleLoader({
|
||||
);
|
||||
}
|
||||
|
||||
if (isRecordingRule(rule)) {
|
||||
if (prometheusRuleType.recordingRule(rule)) {
|
||||
return (
|
||||
<RecordingRuleListItem
|
||||
name={rule.name}
|
||||
|
||||
@@ -13,7 +13,7 @@ import { ListSection } from '../rule-list/components/ListSection';
|
||||
import { groupIdentifier } from '../utils/groupIdentifier';
|
||||
import { createViewLink } from '../utils/misc';
|
||||
import { hashRule } from '../utils/rule-id';
|
||||
import { getRulePluginOrigin, isAlertingRule, isGrafanaRulerRule } from '../utils/rules';
|
||||
import { getRulePluginOrigin, prometheusRuleType, rulerRuleType } from '../utils/rules';
|
||||
|
||||
import { AlertRuleListItem } from './components/AlertRuleListItem';
|
||||
import { RuleActionsButtons } from './components/RuleActionsButtons.V2';
|
||||
@@ -41,7 +41,7 @@ export const StateView = ({ namespaces }: Props) => {
|
||||
// We might hit edge cases where there type = alerting, but there is no state.
|
||||
// In this case, we shouldn't try to group these alerts in the state view
|
||||
// Even though we handle this at the API layer, this is a last catch point for any edge cases
|
||||
if (rule.promRule && isAlertingRule(rule.promRule) && rule.promRule.state) {
|
||||
if (prometheusRuleType.alertingRule(rule.promRule) && rule.promRule.state) {
|
||||
result.get(rule.promRule.state)?.push(rule);
|
||||
}
|
||||
})
|
||||
@@ -97,8 +97,10 @@ const RulesByState = ({ state, rules }: { state: PromAlertingRuleState; rules: C
|
||||
{pageItems.map((rule) => {
|
||||
const { rulerRule, promRule } = rule;
|
||||
|
||||
const isProvisioned = isGrafanaRulerRule(rulerRule) && Boolean(rulerRule.grafana_alert.provenance);
|
||||
const instancesCount = isAlertingRule(rule.promRule) ? calculateTotalInstances(rule.instanceTotals) : undefined;
|
||||
const isProvisioned = rulerRuleType.grafana.rule(rulerRule) && Boolean(rulerRule.grafana_alert.provenance);
|
||||
const instancesCount = prometheusRuleType.alertingRule(rule.promRule)
|
||||
? calculateTotalInstances(rule.instanceTotals)
|
||||
: undefined;
|
||||
const groupId = groupIdentifier.fromCombinedRule(rule);
|
||||
|
||||
if (!promRule) {
|
||||
|
||||
@@ -11,7 +11,7 @@ import { RulerRuleDTO } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { AlertRuleAction, useRulerRuleAbility } from '../../hooks/useAbilities';
|
||||
import * as ruleId from '../../utils/rule-id';
|
||||
import { isGrafanaAlertingRule, isGrafanaRulerRule } from '../../utils/rules';
|
||||
import { isProvisionedRule, rulerRuleType } from '../../utils/rules';
|
||||
import { createRelativeUrl } from '../../utils/url';
|
||||
|
||||
interface Props {
|
||||
@@ -37,7 +37,7 @@ export function RuleActionsButtons({ compact, rule, promRule, groupIdentifier }:
|
||||
{ identifier: RuleIdentifier; isProvisioned: boolean } | undefined
|
||||
>(undefined);
|
||||
|
||||
const isProvisioned = isGrafanaRulerRule(rule) && Boolean(rule.grafana_alert.provenance);
|
||||
const isProvisioned = isProvisionedRule(rule);
|
||||
|
||||
const [editRuleSupported, editRuleAllowed] = useRulerRuleAbility(rule, groupIdentifier, AlertRuleAction.Update);
|
||||
|
||||
@@ -72,7 +72,7 @@ export function RuleActionsButtons({ compact, rule, promRule, groupIdentifier }:
|
||||
handleDuplicateRule={() => setRedirectToClone({ identifier, isProvisioned })}
|
||||
/>
|
||||
{deleteModal}
|
||||
{isGrafanaAlertingRule(rule) && showSilenceDrawer && (
|
||||
{rulerRuleType.grafana.alertingRule(rule) && showSilenceDrawer && (
|
||||
<SilenceGrafanaRuleDrawer rulerRule={rule} onClose={() => setShowSilenceDrawer(false)} />
|
||||
)}
|
||||
{redirectToClone?.identifier && (
|
||||
|
||||
@@ -7,7 +7,8 @@ import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { alertRuleApi } from '../../api/alertRuleApi';
|
||||
import { usePagination } from '../../hooks/usePagination';
|
||||
import { isAlertingRule } from '../../utils/rules';
|
||||
import { Annotation } from '../../utils/constants';
|
||||
import { prometheusRuleType } from '../../utils/rules';
|
||||
|
||||
import { AlertRuleListItem } from './AlertRuleListItem';
|
||||
import { EvaluationGroup } from './EvaluationGroup';
|
||||
@@ -65,7 +66,7 @@ export const EvaluationGroupLoader = ({
|
||||
state={PromAlertingRuleState.Inactive}
|
||||
name={rule.name}
|
||||
href={'/'}
|
||||
summary={isAlertingRule(rule) ? rule.annotations?.summary : undefined}
|
||||
summary={prometheusRuleType.alertingRule(rule) ? rule.annotations?.[Annotation.summary] : undefined}
|
||||
/>;
|
||||
|
||||
return null;
|
||||
|
||||
@@ -21,7 +21,7 @@ import { labelsMatchMatchers } from '../../utils/alertmanager';
|
||||
import { Annotation } from '../../utils/constants';
|
||||
import { getDatasourceAPIUid, getExternalRulesSources } from '../../utils/datasource';
|
||||
import { parseMatcher } from '../../utils/matchers';
|
||||
import { isAlertingRule } from '../../utils/rules';
|
||||
import { prometheusRuleType } from '../../utils/rules';
|
||||
|
||||
import { useGrafanaGroupsGenerator, usePrometheusGroupsGenerator } from './prometheusGroupsGenerator';
|
||||
|
||||
@@ -168,7 +168,7 @@ function ruleFilter(rule: PromRuleDTO, filterState: RulesFilter) {
|
||||
}
|
||||
|
||||
if (filterState.ruleState) {
|
||||
if (!isAlertingRule(rule)) {
|
||||
if (!prometheusRuleType.alertingRule(rule)) {
|
||||
return false;
|
||||
}
|
||||
if (rule.state !== filterState.ruleState) {
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { CombinedRule, RuleGroupIdentifier, RuleGroupIdentifierV2 } from 'app/types/unified-alerting';
|
||||
|
||||
import { GRAFANA_RULES_SOURCE_NAME, getDatasourceAPIUid, getRulesSourceName, isGrafanaRulesSource } from './datasource';
|
||||
import { isGrafanaRulerRule } from './rules';
|
||||
import { rulerRuleType } from './rules';
|
||||
|
||||
function fromCombinedRule(rule: CombinedRule): RuleGroupIdentifierV2 {
|
||||
if (isGrafanaRulerRule(rule.rulerRule) && isGrafanaRulesSource(rule.namespace.rulesSource)) {
|
||||
if (rulerRuleType.grafana.rule(rule.rulerRule) && isGrafanaRulesSource(rule.namespace.rulesSource)) {
|
||||
return {
|
||||
namespace: { uid: rule.rulerRule.grafana_alert.namespace_uid },
|
||||
groupName: rule.group.name,
|
||||
|
||||
@@ -8,7 +8,7 @@ import { CombinedRule } from 'app/types/unified-alerting';
|
||||
import { AlertQuery } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { isCloudRulesSource } from './datasource';
|
||||
import { isGrafanaRulerRule } from './rules';
|
||||
import { rulerRuleType } from './rules';
|
||||
import { safeParsePrometheusDuration } from './time';
|
||||
|
||||
export function alertRuleToQueries(combinedRule: CombinedRule | undefined | null): AlertQuery[] {
|
||||
@@ -18,7 +18,7 @@ export function alertRuleToQueries(combinedRule: CombinedRule | undefined | null
|
||||
const { namespace, rulerRule } = combinedRule;
|
||||
const { rulesSource } = namespace;
|
||||
|
||||
if (isGrafanaRulerRule(rulerRule)) {
|
||||
if (rulerRuleType.grafana.rule(rulerRule)) {
|
||||
const query = rulerRule.grafana_alert.data;
|
||||
return widenRelativeTimeRanges(query, rulerRule.for ?? '', combinedRule.group.interval);
|
||||
}
|
||||
|
||||
@@ -58,14 +58,7 @@ import {
|
||||
isGrafanaRulesSource,
|
||||
} from './datasource';
|
||||
import { arrayToRecord, recordToArray } from './misc';
|
||||
import {
|
||||
isAlertingRulerRule,
|
||||
isGrafanaAlertingRuleByType,
|
||||
isGrafanaRecordingRule,
|
||||
isGrafanaRecordingRuleByType,
|
||||
isGrafanaRulerRule,
|
||||
isRecordingRulerRule,
|
||||
} from './rules';
|
||||
import { isGrafanaAlertingRuleByType, isGrafanaRecordingRuleByType, rulerRuleType } from './rules';
|
||||
import { parseInterval } from './time';
|
||||
|
||||
export type PromOrLokiQuery = PromQuery | LokiQuery;
|
||||
@@ -275,7 +268,7 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
||||
const defaultFormValues = getDefaultFormValues();
|
||||
if (isGrafanaRulesSource(ruleSourceName)) {
|
||||
// GRAFANA-MANAGED RULES
|
||||
if (isGrafanaRecordingRule(rule)) {
|
||||
if (rulerRuleType.grafana.recordingRule(rule)) {
|
||||
// grafana recording rule
|
||||
const ga = rule.grafana_alert;
|
||||
return {
|
||||
@@ -292,7 +285,7 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
||||
isPaused: ga.is_paused,
|
||||
metric: ga.record?.metric,
|
||||
};
|
||||
} else if (isGrafanaRulerRule(rule)) {
|
||||
} else if (rulerRuleType.grafana.rule(rule)) {
|
||||
// grafana alerting rule
|
||||
const ga = rule.grafana_alert;
|
||||
const routingSettings: AlertManagerManualRouting | undefined = getContactPointsFromDTO(ga);
|
||||
@@ -326,7 +319,7 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
||||
}
|
||||
} else {
|
||||
// DATASOURCE-MANAGED RULES
|
||||
if (isAlertingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.alertingRule(rule)) {
|
||||
const datasourceUid = getDataSourceSrv().getInstanceSettings(ruleSourceName)?.uid ?? '';
|
||||
|
||||
const defaultQuery = {
|
||||
@@ -354,7 +347,7 @@ export function rulerRuleToFormValues(ruleWithLocation: RuleWithLocation): RuleF
|
||||
namespace,
|
||||
group: group.name,
|
||||
};
|
||||
} else if (isRecordingRulerRule(rule)) {
|
||||
} else if (rulerRuleType.dataSource.recordingRule(rule)) {
|
||||
const recordingRuleValues = recordingRulerRuleToRuleForm(rule);
|
||||
|
||||
return {
|
||||
|
||||
@@ -18,14 +18,12 @@ import { shouldUsePrometheusRulesPrimary } from '../featureToggles';
|
||||
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from './datasource';
|
||||
import {
|
||||
isAlertingRule,
|
||||
isAlertingRulerRule,
|
||||
getRuleName,
|
||||
isCloudRuleIdentifier,
|
||||
isGrafanaRuleIdentifier,
|
||||
isGrafanaRulerRule,
|
||||
isPrometheusRuleIdentifier,
|
||||
isRecordingRule,
|
||||
isRecordingRulerRule,
|
||||
prometheusRuleType,
|
||||
rulerRuleType,
|
||||
} from './rules';
|
||||
|
||||
export function fromRulerRule(
|
||||
@@ -34,14 +32,14 @@ export function fromRulerRule(
|
||||
groupName: string,
|
||||
rule: RulerRuleDTO
|
||||
): EditableRuleIdentifier {
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
return { uid: rule.grafana_alert.uid!, ruleSourceName: 'grafana' };
|
||||
}
|
||||
return {
|
||||
ruleSourceName,
|
||||
namespace,
|
||||
groupName,
|
||||
ruleName: isAlertingRulerRule(rule) ? rule.alert : rule.record,
|
||||
ruleName: getRuleName(rule),
|
||||
rulerRuleHash: hashRulerRule(rule),
|
||||
} satisfies CloudRuleIdentifier;
|
||||
}
|
||||
@@ -51,7 +49,7 @@ export function fromRulerRuleAndGroupIdentifierV2(
|
||||
rule: RulerRuleDTO
|
||||
): EditableRuleIdentifier {
|
||||
if (ruleGroup.groupOrigin === 'grafana') {
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
return { uid: rule.grafana_alert.uid, ruleSourceName: 'grafana' };
|
||||
}
|
||||
logError(new Error('Rule is not a Grafana Ruler rule'));
|
||||
@@ -260,7 +258,7 @@ export function hash(value: string): number {
|
||||
|
||||
// this is used to identify rules, mimir / loki rules do not have a unique identifier
|
||||
export function hashRulerRule(rule: RulerRuleDTO): string {
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
return rule.grafana_alert.uid;
|
||||
}
|
||||
|
||||
@@ -276,10 +274,10 @@ function getRulerRuleFingerprint(rule: RulerCloudRuleDTO) {
|
||||
const queryHash = prometheusRulesPrimary ? '' : hashQuery(rule.expr);
|
||||
const labelsHash = hashLabelsOrAnnotations(rule.labels);
|
||||
|
||||
if (isRecordingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.recordingRule(rule)) {
|
||||
return [rule.record, PromRuleType.Recording, queryHash, labelsHash];
|
||||
}
|
||||
if (isAlertingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.alertingRule(rule)) {
|
||||
return [rule.alert, PromRuleType.Alerting, queryHash, hashLabelsOrAnnotations(rule.annotations), labelsHash];
|
||||
}
|
||||
throw new Error('Only recording and alerting ruler rules can be hashed');
|
||||
@@ -296,10 +294,10 @@ function getPromRuleFingerprint(rule: Rule) {
|
||||
const queryHash = prometheusRulesPrimary ? '' : hashQuery(rule.query);
|
||||
const labelsHash = hashLabelsOrAnnotations(rule.labels);
|
||||
|
||||
if (isRecordingRule(rule)) {
|
||||
if (prometheusRuleType.recordingRule(rule)) {
|
||||
return [rule.name, PromRuleType.Recording, queryHash, labelsHash];
|
||||
}
|
||||
if (isAlertingRule(rule)) {
|
||||
if (prometheusRuleType.alertingRule(rule)) {
|
||||
return [rule.name, PromRuleType.Alerting, queryHash, hashLabelsOrAnnotations(rule.annotations), labelsHash];
|
||||
}
|
||||
throw new Error('Only recording and alerting rules can be hashed');
|
||||
|
||||
@@ -25,6 +25,8 @@ import {
|
||||
Annotations,
|
||||
GrafanaAlertState,
|
||||
GrafanaAlertStateWithReason,
|
||||
GrafanaAlertingRuleDefinition,
|
||||
GrafanaRecordingRuleDefinition,
|
||||
PostableRuleDTO,
|
||||
PromAlertingRuleState,
|
||||
PromRuleType,
|
||||
@@ -47,49 +49,71 @@ import { GRAFANA_ORIGIN_LABEL } from './labels';
|
||||
import { AsyncRequestState } from './redux';
|
||||
import { formatPrometheusDuration, safeParsePrometheusDuration } from './time';
|
||||
|
||||
export function isAlertingRule(rule: Rule | undefined): rule is AlertingRule {
|
||||
return typeof rule === 'object' && rule.type === PromRuleType.Alerting;
|
||||
}
|
||||
/* Grafana managed rules */
|
||||
|
||||
export function isRecordingRule(rule: Rule | undefined): rule is RecordingRule {
|
||||
return typeof rule === 'object' && rule.type === PromRuleType.Recording;
|
||||
}
|
||||
|
||||
export function isAlertingRulerRule(rule?: RulerRuleDTO): rule is RulerAlertingRuleDTO {
|
||||
return typeof rule === 'object' && 'alert' in rule;
|
||||
}
|
||||
|
||||
export function isRecordingRulerRule(rule?: RulerRuleDTO): rule is RulerRecordingRuleDTO {
|
||||
return typeof rule === 'object' && 'record' in rule;
|
||||
}
|
||||
|
||||
export function isGrafanaOrDataSourceRecordingRule(rule?: RulerRuleDTO) {
|
||||
return (
|
||||
(typeof rule === 'object' && isRecordingRulerRule(rule)) ||
|
||||
(isGrafanaRulerRule(rule) && 'record' in rule.grafana_alert)
|
||||
);
|
||||
}
|
||||
|
||||
export function isGrafanaRecordingRule(rule?: RulerRuleDTO): rule is RulerGrafanaRuleDTO {
|
||||
return typeof rule === 'object' && isGrafanaOrDataSourceRecordingRule(rule) && isGrafanaRulerRule(rule);
|
||||
}
|
||||
|
||||
export function isGrafanaAlertingRule(rule?: RulerRuleDTO): rule is RulerGrafanaRuleDTO {
|
||||
return typeof rule === 'object' && isGrafanaRulerRule(rule) && !isGrafanaOrDataSourceRecordingRule(rule);
|
||||
}
|
||||
|
||||
export function isGrafanaRulerRule(rule?: RulerRuleDTO | PostableRuleDTO): rule is RulerGrafanaRuleDTO {
|
||||
function isGrafanaRulerRule(rule?: RulerRuleDTO | PostableRuleDTO): rule is RulerGrafanaRuleDTO {
|
||||
return typeof rule === 'object' && 'grafana_alert' in rule;
|
||||
}
|
||||
|
||||
export function isCloudRulerRule(rule?: RulerRuleDTO | PostableRuleDTO): rule is RulerCloudRuleDTO {
|
||||
function isGrafanaAlertingRule(rule?: RulerRuleDTO): rule is RulerGrafanaRuleDTO<GrafanaAlertingRuleDefinition> {
|
||||
return isGrafanaRulerRule(rule) && !isGrafanaRecordingRule(rule);
|
||||
}
|
||||
|
||||
function isGrafanaRecordingRule(rule?: RulerRuleDTO): rule is RulerGrafanaRuleDTO<GrafanaRecordingRuleDefinition> {
|
||||
return isGrafanaRulerRule(rule) && 'record' in rule.grafana_alert;
|
||||
}
|
||||
|
||||
export function isPausedRule(rule: RulerGrafanaRuleDTO) {
|
||||
return Boolean(rule.grafana_alert.is_paused);
|
||||
}
|
||||
|
||||
/* Data source managed rules */
|
||||
|
||||
function isAlertingRulerRule(rule?: RulerRuleDTO): rule is RulerAlertingRuleDTO {
|
||||
return typeof rule === 'object' && 'alert' in rule;
|
||||
}
|
||||
|
||||
function isCloudRulerRule(rule?: RulerRuleDTO | PostableRuleDTO): rule is RulerCloudRuleDTO {
|
||||
return typeof rule === 'object' && !isGrafanaRulerRule(rule);
|
||||
}
|
||||
|
||||
export function isGrafanaRulerRulePaused(rule: RulerGrafanaRuleDTO) {
|
||||
return rule && isGrafanaRulerRule(rule) && Boolean(rule.grafana_alert.is_paused);
|
||||
function isCloudRecordingRulerRule(rule?: RulerRuleDTO): rule is RulerRecordingRuleDTO {
|
||||
return typeof rule === 'object' && 'record' in rule;
|
||||
}
|
||||
|
||||
/* Prometheus rules */
|
||||
|
||||
function isAlertingRule(rule?: Rule): rule is AlertingRule {
|
||||
return typeof rule === 'object' && rule.type === PromRuleType.Alerting;
|
||||
}
|
||||
|
||||
function isRecordingRule(rule?: Rule): rule is RecordingRule {
|
||||
return typeof rule === 'object' && rule.type === PromRuleType.Recording;
|
||||
}
|
||||
|
||||
export const rulerRuleType = {
|
||||
grafana: {
|
||||
rule: isGrafanaRulerRule,
|
||||
alertingRule: isGrafanaAlertingRule,
|
||||
recordingRule: isGrafanaRecordingRule,
|
||||
},
|
||||
dataSource: {
|
||||
rule: isCloudRulerRule,
|
||||
alertingRule: isAlertingRulerRule,
|
||||
recordingRule: isCloudRecordingRulerRule,
|
||||
},
|
||||
any: {
|
||||
recordingRule: (rule?: RulerRuleDTO) => isCloudRecordingRulerRule(rule) || isGrafanaRecordingRule(rule),
|
||||
alertingRule: (rule?: RulerRuleDTO) => isAlertingRulerRule(rule) || isGrafanaAlertingRule(rule),
|
||||
},
|
||||
};
|
||||
|
||||
export const prometheusRuleType = {
|
||||
rule: (rule?: Rule) => isAlertingRule(rule) || isRecordingRule(rule),
|
||||
alertingRule: isAlertingRule,
|
||||
recordingRule: isRecordingRule,
|
||||
};
|
||||
|
||||
export function alertInstanceKey(alert: Alert): string {
|
||||
return JSON.stringify(alert.labels);
|
||||
}
|
||||
@@ -139,11 +163,7 @@ export function getRuleHealth(health: string): RuleHealth | undefined {
|
||||
}
|
||||
|
||||
export function getPendingPeriod(rule: CombinedRule): string | undefined {
|
||||
if (
|
||||
isRecordingRulerRule(rule.rulerRule) ||
|
||||
isRecordingRule(rule.promRule) ||
|
||||
isGrafanaRecordingRule(rule.rulerRule)
|
||||
) {
|
||||
if (rulerRuleType.any.recordingRule(rule.rulerRule)) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
@@ -162,16 +182,10 @@ export function getPendingPeriod(rule: CombinedRule): string | undefined {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
export function getAnnotations(rule: CombinedRule): Annotations | undefined {
|
||||
if (
|
||||
isRecordingRulerRule(rule.rulerRule) ||
|
||||
isRecordingRule(rule.promRule) ||
|
||||
isGrafanaRecordingRule(rule.rulerRule)
|
||||
) {
|
||||
return undefined;
|
||||
}
|
||||
return rule.annotations ?? [];
|
||||
export function getAnnotations(rule?: AlertingRule): Annotations {
|
||||
return rule?.annotations ?? {};
|
||||
}
|
||||
|
||||
export interface RulePluginOrigin {
|
||||
pluginId: string;
|
||||
}
|
||||
@@ -300,15 +314,16 @@ export function isFederatedRuleGroup(group: CombinedRuleGroup) {
|
||||
return Array.isArray(group.source_tenants);
|
||||
}
|
||||
|
||||
export function getRuleName(rule: RulerRuleDTO) {
|
||||
if (isGrafanaRulerRule(rule)) {
|
||||
export function getRuleName(rule: RulerRuleDTO): string {
|
||||
if (rulerRuleType.grafana.rule(rule)) {
|
||||
return rule.grafana_alert.title;
|
||||
}
|
||||
if (isAlertingRulerRule(rule)) {
|
||||
|
||||
if (rulerRuleType.dataSource.alertingRule(rule)) {
|
||||
return rule.alert;
|
||||
}
|
||||
|
||||
if (isRecordingRulerRule(rule)) {
|
||||
if (rulerRuleType.dataSource.recordingRule(rule)) {
|
||||
return rule.record;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
|
||||
import { ungroupRulesByFileName } from 'app/features/alerting/unified/api/prometheus';
|
||||
import { Annotation } from 'app/features/alerting/unified/utils/constants';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
|
||||
import { isAlertingRule } from 'app/features/alerting/unified/utils/rules';
|
||||
import { prometheusRuleType } from 'app/features/alerting/unified/utils/rules';
|
||||
import { dispatch } from 'app/store/store';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
import { RuleNamespace } from 'app/types/unified-alerting';
|
||||
@@ -96,7 +96,7 @@ export class AlertStatesDataLayer
|
||||
const panelIdToAlertState: Record<number, AlertStateInfo> = {};
|
||||
groups.forEach((group) =>
|
||||
group.rules.forEach((rule) => {
|
||||
if (isAlertingRule(rule) && rule.annotations && rule.annotations[Annotation.panelID]) {
|
||||
if (prometheusRuleType.alertingRule(rule) && rule.annotations?.[Annotation.panelID]) {
|
||||
this.hasAlertRules = true;
|
||||
const panelId = Number(rule.annotations[Annotation.panelID]);
|
||||
const state = promAlertStateToAlertState(rule.state);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { alertRuleApi } from 'app/features/alerting/unified/api/alertRuleApi';
|
||||
import { ungroupRulesByFileName } from 'app/features/alerting/unified/api/prometheus';
|
||||
import { Annotation } from 'app/features/alerting/unified/utils/constants';
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from 'app/features/alerting/unified/utils/datasource';
|
||||
import { isAlertingRule } from 'app/features/alerting/unified/utils/rules';
|
||||
import { prometheusRuleType } from 'app/features/alerting/unified/utils/rules';
|
||||
import { promAlertStateToAlertState } from 'app/features/dashboard-scene/scene/AlertStatesDataLayer';
|
||||
import { dispatch } from 'app/store/store';
|
||||
import { AccessControlAction } from 'app/types';
|
||||
@@ -82,7 +82,7 @@ export class UnifiedAlertStatesWorker implements DashboardQueryRunnerWorker {
|
||||
const panelIdToAlertState: Record<number, AlertStateInfo> = {};
|
||||
groups.forEach((group) =>
|
||||
group.rules.forEach((rule) => {
|
||||
if (isAlertingRule(rule) && rule.annotations && rule.annotations[Annotation.panelID]) {
|
||||
if (prometheusRuleType.alertingRule(rule) && rule.annotations && rule.annotations[Annotation.panelID]) {
|
||||
this.hasAlertRules[dashboard.uid] = true;
|
||||
const panelId = Number(rule.annotations[Annotation.panelID]);
|
||||
const state = promAlertStateToAlertState(rule.state);
|
||||
|
||||
@@ -10,13 +10,13 @@ import {
|
||||
alertStateToReadable,
|
||||
alertStateToState,
|
||||
getFirstActiveAt,
|
||||
isAlertingRule,
|
||||
prometheusRuleType,
|
||||
} from 'app/features/alerting/unified/utils/rules';
|
||||
import { createRelativeUrl } from 'app/features/alerting/unified/utils/url';
|
||||
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
|
||||
|
||||
import { GRAFANA_RULES_SOURCE_NAME } from '../../../../features/alerting/unified/utils/datasource';
|
||||
import { AlertInstanceTotalState, AlertingRule, CombinedRuleWithLocation } from '../../../../types/unified-alerting';
|
||||
import { AlertInstanceTotalState, CombinedRuleWithLocation } from '../../../../types/unified-alerting';
|
||||
import { AlertInstances } from '../AlertInstances';
|
||||
import { getStyles } from '../UnifiedAlertList';
|
||||
import { UnifiedAlertListOptions } from '../types';
|
||||
@@ -47,7 +47,7 @@ const UngroupedModeView = ({ rules, options, handleInstancesLimit, limitInstance
|
||||
<ol className={styles.alertRuleList}>
|
||||
{rulesToDisplay.map((ruleWithLocation, index) => {
|
||||
const { namespaceName, groupName, dataSourceName } = ruleWithLocation;
|
||||
const alertingRule: AlertingRule | undefined = isAlertingRule(ruleWithLocation.promRule)
|
||||
const alertingRule = prometheusRuleType.alertingRule(ruleWithLocation.promRule)
|
||||
? ruleWithLocation.promRule
|
||||
: undefined;
|
||||
const firstActiveAt = getFirstActiveAt(alertingRule);
|
||||
|
||||
@@ -278,6 +278,12 @@ export interface GrafanaRuleDefinition extends PostableGrafanaRuleDefinition {
|
||||
version?: number;
|
||||
}
|
||||
|
||||
// types for Grafana-managed recording and alerting rules
|
||||
export type GrafanaAlertingRuleDefinition = Omit<GrafanaRuleDefinition, 'record'>;
|
||||
export type GrafanaRecordingRuleDefinition = GrafanaRuleDefinition & {
|
||||
record: GrafanaRuleDefinition['record'];
|
||||
};
|
||||
|
||||
export interface RulerGrafanaRuleDTO<T = GrafanaRuleDefinition> {
|
||||
grafana_alert: T;
|
||||
for?: string;
|
||||
|
||||
Reference in New Issue
Block a user