{}
diff --git a/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx b/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx
index 0051f562af8..a9a6014380f 100644
--- a/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx
+++ b/public/app/features/alerting/unified/components/rules/RuleDetailsActionButtons.tsx
@@ -1,22 +1,10 @@
import { css } from '@emotion/css';
import { uniqueId } from 'lodash';
import React, { Fragment, useState } from 'react';
-import { useLocation } from 'react-router-dom';
-import { GrafanaTheme2, textUtil, urlUtil } from '@grafana/data';
+import { GrafanaTheme2, textUtil } from '@grafana/data';
import { config, useReturnToPrevious } from '@grafana/runtime';
-import {
- Button,
- ClipboardButton,
- ConfirmModal,
- Dropdown,
- HorizontalGroup,
- Icon,
- LinkButton,
- Menu,
- useStyles2,
-} from '@grafana/ui';
-import { useAppNotification } from 'app/core/copy/appNotification';
+import { Button, ConfirmModal, Dropdown, HorizontalGroup, Icon, LinkButton, Menu, useStyles2 } from '@grafana/ui';
import { useDispatch } from 'app/types';
import { CombinedRule, RuleIdentifier, RulesSource } from 'app/types/unified-alerting';
import { PromAlertingRuleState } from 'app/types/unified-alerting-dto';
@@ -36,7 +24,6 @@ import {
} from '../../utils/misc';
import * as ruleId from '../../utils/rule-id';
import { isAlertingRule, isFederatedRuleGroup, isGrafanaRulerRule } from '../../utils/rules';
-import { createUrl } from '../../utils/url';
import { DeclareIncidentButton } from '../bridges/DeclareIncidentButton';
import { RedirectToCloneRule } from './CloneRule';
@@ -44,16 +31,13 @@ import { RedirectToCloneRule } from './CloneRule';
interface Props {
rule: CombinedRule;
rulesSource: RulesSource;
- isViewMode: boolean;
}
-export const RuleDetailsActionButtons = ({ rule, rulesSource, isViewMode }: Props) => {
+export const RuleDetailsActionButtons = ({ rule, rulesSource }: Props) => {
const style = useStyles2(getStyles);
- const { namespace, group, rulerRule } = rule;
+ const { group } = rule;
const { StateHistoryModal, showStateHistoryModal } = useStateHistoryModal();
const dispatch = useDispatch();
- const location = useLocation();
- const notifyApp = useAppNotification();
const setReturnToPrevious = useReturnToPrevious();
@@ -66,11 +50,8 @@ export const RuleDetailsActionButtons = ({ rule, rulesSource, isViewMode }: Prop
? rulesSource
: getAlertmanagerByUid(rulesSource.jsonData.alertmanagerUid)?.name;
- const [duplicateSupported, duplicateAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Duplicate);
const [silenceSupported, silenceAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Silence);
const [exploreSupported, exploreAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Explore);
- const [deleteSupported, deleteAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Delete);
- const [editSupported, editAllowed] = useAlertRuleAbility(rule, AlertRuleAction.Update);
const buttons: JSX.Element[] = [];
const rightButtons: JSX.Element[] = [];
@@ -85,24 +66,19 @@ export const RuleDetailsActionButtons = ({ rule, rulesSource, isViewMode }: Prop
ruleToDelete.rulerRule
);
- dispatch(deleteRuleAction(identifier, { navigateTo: isViewMode ? '/alerting/list' : undefined }));
+ dispatch(deleteRuleAction(identifier, { navigateTo: undefined }));
setRuleToDelete(undefined);
}
};
const isFederated = isFederatedRuleGroup(group);
- const isProvisioned = isGrafanaRulerRule(rule.rulerRule) && Boolean(rule.rulerRule.grafana_alert.provenance);
const isFiringRule = isAlertingRule(rule.promRule) && rule.promRule.state === PromAlertingRuleState.Firing;
- const canDelete = deleteSupported && deleteAllowed;
- const canEdit = editSupported && editAllowed;
const canSilence = silenceSupported && silenceAllowed && alertmanagerSourceName;
- const canDuplicateRule = duplicateSupported && duplicateAllowed && !isFederated;
const buildShareUrl = () => createShareLink(rulesSource, rule);
- const returnTo = location.pathname + location.search;
// explore does not support grafana rule queries atm
// neither do "federated rules"
if (isCloudRulesSource(rulesSource) && exploreSupported && exploreAllowed && !isFederated) {
@@ -210,63 +186,6 @@ export const RuleDetailsActionButtons = ({ rule, rulesSource, isViewMode }: Prop
);
}
- if (isViewMode && rulerRule) {
- const sourceName = getRulesSourceName(rulesSource);
- const identifier = ruleId.fromRulerRule(sourceName, namespace.name, group.name, rulerRule);
-
- if (canEdit) {
- rightButtons.push(
- {
- notifyApp.error('Error while copying URL', copiedText);
- }}
- size="sm"
- getText={buildShareUrl}
- >
- Copy link to rule
-
- );
-
- if (!isProvisioned) {
- const editURL = urlUtil.renderUrl(
- `${config.appSubUrl}/alerting/${encodeURIComponent(ruleId.stringifyIdentifier(identifier))}/edit`,
- {
- returnTo,
- }
- );
-
- rightButtons.push(
-
- Edit
-
- );
- }
- }
-
- if (isGrafanaRulerRule(rulerRule)) {
- const modifyUrl = createUrl(
- `/alerting/${encodeURIComponent(ruleId.stringifyIdentifier(identifier))}/modify-export`
- );
-
- moreActionsButtons.push(
);
- }
-
- if (canDuplicateRule) {
- moreActionsButtons.push(
- setRedirectToClone({ identifier, isProvisioned })} />
- );
- }
-
- if (canDelete) {
- moreActionsButtons.push();
- moreActionsButtons.push(
- setRuleToDelete(rule)} />
- );
- }
- }
-
if (buttons.length || rightButtons.length || moreActionsButtons.length) {
return (
<>
diff --git a/public/app/features/alerting/unified/utils/query.ts b/public/app/features/alerting/unified/utils/query.ts
index 0f5648638a6..bde53876d92 100644
--- a/public/app/features/alerting/unified/utils/query.ts
+++ b/public/app/features/alerting/unified/utils/query.ts
@@ -1,3 +1,5 @@
+import { produce } from 'immer';
+
import { DataSourceInstanceSettings } from '@grafana/data';
import { DataQuery } from '@grafana/schema';
import { LokiQuery } from 'app/plugins/datasource/loki/types';
@@ -5,8 +7,9 @@ import { PromQuery } from 'app/plugins/datasource/prometheus/types';
import { CombinedRule } from 'app/types/unified-alerting';
import { AlertQuery } from 'app/types/unified-alerting-dto';
-import { isCloudRulesSource, isGrafanaRulesSource } from './datasource';
+import { isCloudRulesSource } from './datasource';
import { isGrafanaRulerRule } from './rules';
+import { safeParseDurationstr } from './time';
export function alertRuleToQueries(combinedRule: CombinedRule | undefined | null): AlertQuery[] {
if (!combinedRule) {
@@ -15,10 +18,9 @@ export function alertRuleToQueries(combinedRule: CombinedRule | undefined | null
const { namespace, rulerRule } = combinedRule;
const { rulesSource } = namespace;
- if (isGrafanaRulesSource(rulesSource)) {
- if (isGrafanaRulerRule(rulerRule)) {
- return rulerRule.grafana_alert.data;
- }
+ if (isGrafanaRulerRule(rulerRule)) {
+ const query = rulerRule.grafana_alert.data;
+ return widenRelativeTimeRanges(query, rulerRule.for, combinedRule.group.interval);
}
if (isCloudRulesSource(rulesSource)) {
@@ -30,6 +32,37 @@ export function alertRuleToQueries(combinedRule: CombinedRule | undefined | null
return [];
}
+/**
+ * This function will figure out how large the time range for visualizing the alert rule detail view should be
+ * We try to show as much data as is relevant for triaging / root cause analysis
+ *
+ * The function for it is;
+ *
+ * Math.max(3 * pending period, query range + (2 * pending period))
+ *
+ * We can safely ignore the evaluation interval because the pending period is guaranteed to be largen than or equal that
+ */
+export function widenRelativeTimeRanges(queries: AlertQuery[], pendingPeriod: string, groupInterval?: string) {
+ // if pending period is zero that means inherit from group interval, if that is empty then assume 1m
+ const pendingPeriodDurationMillis =
+ safeParseDurationstr(pendingPeriod) ?? safeParseDurationstr(groupInterval ?? '1m');
+ const pendingPeriodDuration = Math.floor(pendingPeriodDurationMillis / 1000);
+
+ return queries.map((query) =>
+ produce(query, (draft) => {
+ const fromQueryRange = draft.relativeTimeRange?.from ?? 0;
+
+ // use whichever has the largest time range
+ const from = Math.max(pendingPeriodDuration * 3, fromQueryRange + pendingPeriodDuration * 2);
+
+ draft.relativeTimeRange = {
+ from,
+ to: 0,
+ };
+ })
+ );
+}
+
export function dataQueryToAlertQuery(dataQuery: DataQuery, dataSourceUid: string): AlertQuery {
return {
refId: dataQuery.refId,