link to the explore view from the metric name in the detail view

This commit is contained in:
Sonia Aguilar 2024-08-29 10:50:25 +02:00
parent 5439d99d07
commit 3c17d16cf6
5 changed files with 49 additions and 4 deletions

View File

@ -72,6 +72,7 @@ export interface UnifiedAlertingConfig {
alertStateHistoryBackend?: string;
// will be undefined if implementation is not "multiple"
alertStateHistoryPrimary?: string;
grafanaRecordingRulesUrl?: string;
}
/** Supported OAuth services

View File

@ -152,6 +152,7 @@ export class GrafanaBootConfig implements GrafanaConfig {
minInterval: '',
alertStateHistoryBackend: undefined,
alertStateHistoryPrimary: undefined,
grafanaRecordingRulesUrl: undefined,
};
applicationInsightsConnectionString?: string;
applicationInsightsEndpointUrl?: string;

View File

@ -95,6 +95,7 @@ type FrontendSettingsUnifiedAlertingDTO struct {
MinInterval string `json:"minInterval"`
AlertStateHistoryBackend string `json:"alertStateHistoryBackend,omitempty"`
AlertStateHistoryPrimary string `json:"alertStateHistoryPrimary,omitempty"`
GrafanaRecordingRulesUrl string `json:"grafanaRecordingRulesUrl,omitempty"`
}
// Enterprise-only

View File

@ -329,6 +329,9 @@ func (hs *HTTPServer) getFrontendSettings(c *contextmodel.ReqContext) (*dtos.Fro
if hs.Cfg.UnifiedAlerting.Enabled != nil {
frontendSettings.UnifiedAlertingEnabled = *hs.Cfg.UnifiedAlerting.Enabled
}
if hs.Cfg.UnifiedAlerting.RecordingRules.Enabled {
frontendSettings.UnifiedAlerting.GrafanaRecordingRulesUrl = hs.Cfg.UnifiedAlerting.RecordingRules.URL
}
// It returns false if the provider is not enabled or the skip org role sync is false.
parseSkipOrgRoleSyncEnabled := func(info *social.OAuthInfo) bool {

View File

@ -3,6 +3,7 @@ import { chain, isEmpty, truncate } from 'lodash';
import { useState } from 'react';
import { NavModelItem, UrlQueryValue } from '@grafana/data';
import { config } from '@grafana/runtime';
import { Alert, LinkButton, Stack, TabContent, Text, TextLink, useStyles2 } from '@grafana/ui';
import { PageInfoItem } from 'app/core/components/Page/types';
import { useQueryParams } from 'app/core/hooks/useQueryParams';
@ -13,6 +14,7 @@ import { PromAlertingRuleState, PromRuleType } from 'app/types/unified-alerting-
import { defaultPageNav } from '../../RuleViewer';
import { PluginOriginBadge } from '../../plugins/PluginOriginBadge';
import { getAllDataSources } from '../../utils/config';
import { Annotation } from '../../utils/constants';
import { makeDashboardLink, makePanelLink } from '../../utils/misc';
import {
@ -195,10 +197,41 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
}
if (isGrafanaRecordingRule(rule.rulerRule)) {
const metric = rule.rulerRule?.grafana_alert.record?.metric ?? '';
metadata.push({
label: 'Metric name',
value: <Text color="primary">{metric}</Text>,
});
const dSWithRecordingRulesUrl = getDataSourceForRecordingRules();
if (dSWithRecordingRulesUrl) {
// if we have a datasource with recording rules, we can link to explore with the datasource and metric in the query
const exploreLink = createRelativeUrl('/explore', {
left: JSON.stringify({
datasource: dSWithRecordingRulesUrl.uid,
queries: [
{
refId: 'A',
datasource: { type: dSWithRecordingRulesUrl.type, uid: dSWithRecordingRulesUrl.uid },
expr: `${metric}{}`,
},
],
range: { from: 'now-1h', to: 'now' },
}),
});
metadata.push({
label: 'Metric name',
value: (
<TextLink variant="bodySmall" href={exploreLink} external>
{metric}
</TextLink>
),
});
} else {
// if we don't have a datasource with recording rules, we can just show the metric name
// this can happen if the datasource with the url specified in the config is not added as a datasource in Grafana
metadata.push({
label: 'Metric name',
value: <Text color="primary">{metric}</Text>,
});
}
}
if (interval) {
@ -219,6 +252,12 @@ const createMetadata = (rule: CombinedRule): PageInfoItem[] => {
return metadata;
};
function getDataSourceForRecordingRules() {
const urlForRecordingRules = config.unifiedAlerting.grafanaRecordingRulesUrl;
const allDs = getAllDataSources();
return allDs.find((ds) => ds.url === urlForRecordingRules);
}
// TODO move somewhere else
export const createListFilterLink = (values: Array<[string, string]>) => {
const params = new URLSearchParams([['search', values.map(([key, value]) => `${key}:"${value}"`).join(' ')]]);