Grafana OnCall
diff --git a/grafana-plugin/src/pages/index.tsx b/grafana-plugin/src/pages/index.tsx
index 280c80e7..99278aa0 100644
--- a/grafana-plugin/src/pages/index.tsx
+++ b/grafana-plugin/src/pages/index.tsx
@@ -142,6 +142,12 @@ export const pages: { [id: string]: PageDefinition } = [
path: getPath('cloud'),
action: UserActions.OtherSettingsWrite,
},
+ {
+ icon: 'cloud',
+ id: 'insights',
+ text: 'Insights',
+ path: getPath('insights'),
+ },
{
icon: 'cog',
id: 'test',
@@ -180,6 +186,7 @@ export const ROUTES = {
'chat-ops': ['chat-ops'],
'live-settings': ['live-settings'],
cloud: ['cloud'],
+ insights: ['insights'],
test: ['test'],
// backwards compatible to redirect to new alert-groups
diff --git a/grafana-plugin/src/pages/insights/Insights.helpers.ts b/grafana-plugin/src/pages/insights/Insights.helpers.ts
new file mode 100644
index 00000000..eb09252e
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/Insights.helpers.ts
@@ -0,0 +1,4 @@
+import { DataSourceRef } from '@grafana/schema';
+
+export const getDataSource = (isOpenSource: boolean): DataSourceRef =>
+ isOpenSource ? { uid: '$datasource' } : { uid: 'grafanacloud-usage' };
diff --git a/grafana-plugin/src/pages/insights/Insights.tsx b/grafana-plugin/src/pages/insights/Insights.tsx
new file mode 100644
index 00000000..5441a5fb
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/Insights.tsx
@@ -0,0 +1,170 @@
+import React, { useMemo, useState } from 'react';
+
+import {
+ EmbeddedScene,
+ SceneTimeRange,
+ SceneFlexLayout,
+ SceneControlsSpacer,
+ SceneRefreshPicker,
+ SceneTimePicker,
+ SceneVariableSet,
+ VariableValueSelectors,
+ NestedScene,
+} from '@grafana/scenes';
+import { Alert } from '@grafana/ui';
+import { observer } from 'mobx-react';
+
+import Text from 'components/Text/Text';
+import { useStore } from 'state/useStore';
+import { DOCS_ROOT } from 'utils/consts';
+
+import { getDataSource } from './Insights.helpers';
+import { InsightsConfig } from './Insights.types';
+import getAlertGroupsByIntegrationScene from './scenes/AlertGroupsByIntegration';
+import getAlertGroupsByTeamScene from './scenes/AlertGroupsByTeam';
+import getMTTRScene from './scenes/MTTR';
+import getMTTRByIntegrationScene from './scenes/MTTRByIntegration';
+import getMTTRByTeamScene from './scenes/MTTRByTeam';
+import getMTTRChangedForPeriodStatScene from './scenes/MTTRChangedForPeriodStat';
+import getMTTRChangedForPeriodTimeseriesScene from './scenes/MTTRChangedForPeriodTimeseries';
+import getNewAlertGroupsDuringTimePeriodScene from './scenes/NewAlertGroupsDuringTimePeriod';
+import getNewAlertGroupsForSelectedPeriodScene from './scenes/NewAlertGroupsForSelectedPeriod';
+import getNewAlertGroupsNotificationsDuringTimePeriodScene from './scenes/NewAlertGroupsNotificationsDuringTimePeriod';
+import getNewAlertGroupsNotificationsForPeriodTableScene from './scenes/NewAlertGroupsNotificationsForPeriodTable';
+import getNewAlertGroupsNotificationsInTotalScene from './scenes/NewAlertGroupsNotificationsInTotal';
+import getTotalAlertGroupsScene from './scenes/TotalAlertGroups';
+import getTotalAlertGroupsByStateScene from './scenes/TotalAlertGroupsByState';
+import getVariables from './variables';
+
+const Insights = observer(() => {
+ const { isOpenSource } = useStore();
+ const [alertVisible, setAlertVisible] = useState(true);
+
+ const rootScene = useMemo(
+ () => getRootScene({ isOpenSource, datasource: getDataSource(isOpenSource) }),
+ [isOpenSource]
+ );
+
+ return (
+ <>
+ {isOpenSource && alertVisible && (
+
setAlertVisible(false)} severity="info" title="">
+ {
+ <>
+ In order to see insights you need to set up Prometheus, add it to your Grafana instance as a data source,
+ set FEATURE_PROMETHEUS_EXPORTER_ENABLED environment variable to true and then select your Data source in
+ the dropdown below.
+
+
+ <>
+ You can find out more in
+
+ documentation
+
+ .
+ >
+ >
+ }
+
+ )}
+
+ >
+ );
+});
+
+const getRootScene = (config: InsightsConfig) =>
+ new EmbeddedScene({
+ $timeRange: new SceneTimeRange({ from: 'now-7d', to: 'now' }),
+ $variables: new SceneVariableSet({
+ variables: getVariables(config),
+ }),
+ controls: [
+ new VariableValueSelectors({}),
+ new SceneControlsSpacer(),
+ new SceneTimePicker({}),
+ new SceneRefreshPicker({}),
+ ],
+ body: new SceneFlexLayout({
+ direction: 'column',
+ children: [
+ new NestedScene({
+ title: 'Overview',
+ canCollapse: true,
+ isCollapsed: false,
+ body: new SceneFlexLayout({
+ direction: 'column',
+ children: [
+ new SceneFlexLayout({
+ height: 200,
+ children: [
+ getTotalAlertGroupsScene(config),
+ getTotalAlertGroupsByStateScene(config),
+ getNewAlertGroupsForSelectedPeriodScene(config),
+ getMTTRScene(config),
+ getMTTRChangedForPeriodStatScene(config),
+ ],
+ }),
+ new SceneFlexLayout({
+ height: 400,
+ children: [getNewAlertGroupsDuringTimePeriodScene(config)],
+ }),
+ new SceneFlexLayout({
+ height: 400,
+ children: [getMTTRChangedForPeriodTimeseriesScene(config)],
+ }),
+ ],
+ }),
+ }),
+ new NestedScene({
+ title: 'Integrations data',
+ canCollapse: true,
+ isCollapsed: false,
+ body: new SceneFlexLayout({
+ height: 400,
+ children: [getAlertGroupsByIntegrationScene(config), getMTTRByIntegrationScene(config)],
+ }),
+ }),
+ new NestedScene({
+ title: 'Notified alert groups by Users (based on all Integrations)',
+ canCollapse: true,
+ isCollapsed: false,
+ body: new SceneFlexLayout({
+ direction: 'column',
+ children: [
+ new SceneFlexLayout({
+ height: 400,
+ children: [getNewAlertGroupsNotificationsDuringTimePeriodScene(config)],
+ }),
+ new SceneFlexLayout({
+ height: 400,
+ children: [
+ getNewAlertGroupsNotificationsInTotalScene(config),
+ getNewAlertGroupsNotificationsForPeriodTableScene(config),
+ ],
+ }),
+ ],
+ }),
+ }),
+ new NestedScene({
+ title: 'Teams data',
+ canCollapse: true,
+ isCollapsed: false,
+ body: new SceneFlexLayout({
+ direction: 'column',
+ children: [
+ new SceneFlexLayout({
+ height: 400,
+ children: [getAlertGroupsByTeamScene(config), getMTTRByTeamScene(config)],
+ }),
+ ],
+ }),
+ }),
+ ],
+ }),
+ });
+
+export default Insights;
diff --git a/grafana-plugin/src/pages/insights/Insights.types.ts b/grafana-plugin/src/pages/insights/Insights.types.ts
new file mode 100644
index 00000000..912585a9
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/Insights.types.ts
@@ -0,0 +1,6 @@
+import { DataSourceRef } from '@grafana/schema';
+
+export interface InsightsConfig {
+ isOpenSource: boolean;
+ datasource: DataSourceRef;
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/AlertGroupsByIntegration.tsx b/grafana-plugin/src/pages/insights/scenes/AlertGroupsByIntegration.tsx
new file mode 100644
index 00000000..07e2a102
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/AlertGroupsByIntegration.tsx
@@ -0,0 +1,111 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getAlertGroupsByIntegrationScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(max_over_time(sum by(integration) (avg without(pod, instance)($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))[1d:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'Alert groups',
+ integration: 'Integration',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'Alert groups by Integration',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ custom: {
+ align: 'auto',
+ cellOptions: {
+ mode: 'gradient',
+ type: 'gauge',
+ valueDisplayMode: 'color',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Integration',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/AlertGroupsByTeam.tsx b/grafana-plugin/src/pages/insights/scenes/AlertGroupsByTeam.tsx
new file mode 100644
index 00000000..2df8f305
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/AlertGroupsByTeam.tsx
@@ -0,0 +1,111 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getAlertGroupsByTeamScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(max_over_time(sum by(team) (avg without(pod, instance)($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))[1d:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'Alert groups',
+ team: 'Team',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'Alert groups by Team',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ custom: {
+ align: 'auto',
+ cellOptions: {
+ mode: 'gradient',
+ type: 'gauge',
+ valueDisplayMode: 'color',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Team',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/MTTR.tsx b/grafana-plugin/src/pages/insights/scenes/MTTR.tsx
new file mode 100644
index 00000000..a8849465
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/MTTR.tsx
@@ -0,0 +1,74 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getMTTRScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'avg_over_time((sum($alert_groups_response_time_seconds_sum{slug=~"$instance", team=~"$team", integration=~"$integration"}) / sum($alert_groups_response_time_seconds_count{slug=~"$instance", team=~"$team", integration=~"$integration"}))[$__range:])',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'Mean time to respond (MTTR)',
+ description: 'Mean time between the start and first action of all alert groups for the last 7 days',
+ pluginId: 'stat',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'text',
+ value: null,
+ },
+ ],
+ },
+ unit: 's',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Value',
+ },
+ properties: [
+ {
+ id: 'displayName',
+ value: 'MTTR',
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ colorMode: 'value',
+ graphMode: 'none',
+ justifyMode: 'center',
+ orientation: 'auto',
+ reduceOptions: {
+ calcs: ['lastNotNull'],
+ fields: '',
+ values: false,
+ },
+ textMode: 'auto',
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/MTTRByIntegration.tsx b/grafana-plugin/src/pages/insights/scenes/MTTRByIntegration.tsx
new file mode 100644
index 00000000..384a247c
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/MTTRByIntegration.tsx
@@ -0,0 +1,126 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getMTTRByIntegrationScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(avg_over_time((sum by (integration)($alert_groups_response_time_seconds_sum{slug=~"$instance", team=~"$team", integration=~"$integration"}) / sum by (integration)($alert_groups_response_time_seconds_count{slug=~"$instance", team=~"$team", integration=~"$integration"}))[$__range:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ cluster: true,
+ container: true,
+ id: true,
+ instance: true,
+ job: true,
+ namespace: true,
+ org_id: true,
+ pod: true,
+ slug: true,
+ team: true,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'MTTR',
+ integration: 'Integration',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'Mean time to respond (MTTR) by Integration',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'continuous-GrYlRd',
+ },
+ custom: {
+ align: 'auto',
+ cellOptions: {
+ mode: 'gradient',
+ type: 'gauge',
+ valueDisplayMode: 'text',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: 0,
+ },
+ {
+ color: 'red',
+ value: 5400,
+ },
+ ],
+ },
+ unit: 's',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Integration',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/MTTRByTeam.tsx b/grafana-plugin/src/pages/insights/scenes/MTTRByTeam.tsx
new file mode 100644
index 00000000..e193546f
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/MTTRByTeam.tsx
@@ -0,0 +1,116 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getMTTRByTeamScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(avg_over_time((sum by(team) ($alert_groups_response_time_seconds_sum{slug=~"$instance", team=~"$team", integration=~"$integration"}) / sum by(team)($alert_groups_response_time_seconds_count{slug=~"$instance", team=~"$team", integration=~"$integration"}))[$__range:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'MTTR',
+ team: 'Team',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'Mean time to respond by Team (MTTR)',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'continuous-GrYlRd',
+ },
+ custom: {
+ align: 'left',
+ cellOptions: {
+ mode: 'gradient',
+ type: 'gauge',
+ valueDisplayMode: 'text',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ {
+ color: 'red',
+ value: 5400,
+ },
+ ],
+ },
+ unit: 's',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Team',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodStat.tsx b/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodStat.tsx
new file mode 100644
index 00000000..11000fd7
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodStat.tsx
@@ -0,0 +1,68 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getMTTRChangedForPeriodStatScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'avg(sum($alert_groups_response_time_seconds_sum{slug=~"$instance", team=~"$team", integration=~"$integration"}) / sum($alert_groups_response_time_seconds_count{slug=~"$instance", team=~"$team", integration=~"$integration"}))',
+ instant: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'MTTR changed for period',
+ pluginId: 'stat',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'blue',
+ value: null,
+ },
+ {
+ color: 'green',
+ value: -10000000,
+ },
+ {
+ color: 'super-light-yellow',
+ value: 0,
+ },
+ ],
+ },
+ unit: 's',
+ },
+ overrides: [],
+ },
+ options: {
+ colorMode: 'value',
+ graphMode: 'none',
+ justifyMode: 'center',
+ orientation: 'auto',
+ reduceOptions: {
+ calcs: ['diff'],
+ fields: '',
+ values: false,
+ },
+ textMode: 'auto',
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodTimeseries.tsx b/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodTimeseries.tsx
new file mode 100644
index 00000000..c5f37f2c
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/MTTRChangedForPeriodTimeseries.tsx
@@ -0,0 +1,107 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getMTTRChangedForPeriodTimeseriesScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'avg(sum($alert_groups_response_time_seconds_sum{slug=~"$instance", team=~"$team", integration=~"$integration"}) / sum($alert_groups_response_time_seconds_count{slug=~"$instance", team=~"$team", integration=~"$integration"}))',
+ instant: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'MTTR changed for period',
+ pluginId: 'timeseries',
+ fieldConfig: {
+ defaults: {
+ color: {
+ fixedColor: 'green',
+ mode: 'fixed',
+ seriesBy: 'min',
+ },
+ custom: {
+ axisCenteredZero: false,
+ axisColorMode: 'text',
+ axisLabel: '',
+ axisPlacement: 'auto',
+ barAlignment: 0,
+ drawStyle: 'line',
+ fillOpacity: 54,
+ gradientMode: 'opacity',
+ hideFrom: {
+ legend: false,
+ tooltip: false,
+ viz: false,
+ },
+ lineInterpolation: 'linear',
+ lineStyle: {
+ fill: 'solid',
+ },
+ lineWidth: 1,
+ pointSize: 5,
+ scaleDistribution: {
+ type: 'linear',
+ },
+ showPoints: 'auto',
+ spanNulls: true,
+ stacking: {
+ group: 'A',
+ mode: 'none',
+ },
+ thresholdsStyle: {
+ mode: 'off',
+ },
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'text',
+ value: 0,
+ },
+ ],
+ },
+ unit: 's',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Value',
+ },
+ properties: [
+ {
+ id: 'displayName',
+ value: 'MTTR',
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ legend: {
+ displayMode: 'list',
+ placement: 'bottom',
+ showLegend: false,
+ },
+ tooltip: {
+ mode: 'single',
+ sort: 'none',
+ },
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsDuringTimePeriod.tsx b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsDuringTimePeriod.tsx
new file mode 100644
index 00000000..16033da3
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsDuringTimePeriod.tsx
@@ -0,0 +1,118 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getNewAlertGroupsDuringTimePeriodScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ disableTextWrap: false,
+ editorMode: 'code',
+ excludeNullMetadata: false,
+ exemplar: false,
+ expr: 'increase(max_over_time(sum by (integration) (avg without(pod, instance) ($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))[30m:])[1h:])',
+ fullMetaSearch: false,
+ instant: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ useBackend: false,
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'New alert groups during time period',
+ pluginId: 'timeseries',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'palette-classic',
+ },
+ custom: {
+ axisCenteredZero: false,
+ axisColorMode: 'text',
+ axisLabel: '',
+ axisPlacement: 'auto',
+ barAlignment: 0,
+ drawStyle: 'line',
+ fillOpacity: 80,
+ gradientMode: 'opacity',
+ hideFrom: {
+ legend: false,
+ tooltip: false,
+ viz: false,
+ },
+ lineInterpolation: 'linear',
+ lineStyle: {
+ fill: 'solid',
+ },
+ lineWidth: 1,
+ pointSize: 5,
+ scaleDistribution: {
+ type: 'linear',
+ },
+ showPoints: 'auto',
+ spanNulls: false,
+ stacking: {
+ group: 'A',
+ mode: 'normal',
+ },
+ thresholdsStyle: {
+ mode: 'off',
+ },
+ },
+ decimals: 0,
+ displayName: '${__field.labels.integration}',
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byValue',
+ options: {
+ op: 'gte',
+ reducer: 'allIsZero',
+ value: 0,
+ },
+ },
+ properties: [
+ {
+ id: 'custom.hideFrom',
+ value: {
+ legend: true,
+ tooltip: true,
+ viz: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ legend: {
+ displayMode: 'list',
+ placement: 'bottom',
+ showLegend: true,
+ },
+ tooltip: {
+ mode: 'multi',
+ sort: 'desc',
+ },
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsForSelectedPeriod.tsx b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsForSelectedPeriod.tsx
new file mode 100644
index 00000000..f38abacb
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsForSelectedPeriod.tsx
@@ -0,0 +1,80 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getNewAlertGroupsForSelectedPeriodScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ disableTextWrap: false,
+ editorMode: 'code',
+ excludeNullMetadata: false,
+ exemplar: false,
+ expr: 'increase(max_over_time(sum(avg without(pod, instance) ($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))[1d:])[$__range:])',
+ format: 'time_series',
+ fullMetaSearch: false,
+ includeNullMetadata: true,
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ useBackend: false,
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'New alert groups for selected period',
+ pluginId: 'stat',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ decimals: 0,
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'text',
+ value: null,
+ },
+ ],
+ },
+ unit: 'none',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Value',
+ },
+ properties: [
+ {
+ id: 'displayName',
+ value: 'New alert groups',
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ colorMode: 'value',
+ graphMode: 'none',
+ justifyMode: 'center',
+ orientation: 'auto',
+ reduceOptions: {
+ calcs: ['lastNotNull'],
+ fields: '',
+ values: false,
+ },
+ textMode: 'auto',
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsDuringTimePeriod.tsx b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsDuringTimePeriod.tsx
new file mode 100644
index 00000000..328da56b
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsDuringTimePeriod.tsx
@@ -0,0 +1,118 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getNewAlertGroupsNotificationsDuringTimePeriodScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ disableTextWrap: false,
+ editorMode: 'code',
+ excludeNullMetadata: false,
+ exemplar: false,
+ expr: 'increase(max_over_time(sum by (username) (avg without(pod, instance) ($user_was_notified_of_alert_groups_total{slug=~"$instance"}))[30m:])[1h:])',
+ fullMetaSearch: false,
+ instant: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ useBackend: false,
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ title: 'New alert groups notifications during time period',
+ pluginId: 'timeseries',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'palette-classic',
+ },
+ custom: {
+ axisCenteredZero: false,
+ axisColorMode: 'text',
+ axisLabel: '',
+ axisPlacement: 'auto',
+ barAlignment: 0,
+ drawStyle: 'line',
+ fillOpacity: 80,
+ gradientMode: 'opacity',
+ hideFrom: {
+ legend: false,
+ tooltip: false,
+ viz: false,
+ },
+ insertNulls: false,
+ lineInterpolation: 'linear',
+ lineStyle: {
+ fill: 'solid',
+ },
+ lineWidth: 1,
+ pointSize: 5,
+ scaleDistribution: {
+ type: 'linear',
+ },
+ showPoints: 'auto',
+ spanNulls: false,
+ stacking: {
+ group: 'A',
+ mode: 'normal',
+ },
+ thresholdsStyle: {
+ mode: 'off',
+ },
+ },
+ decimals: 0,
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byValue',
+ options: {
+ op: 'gte',
+ reducer: 'allIsZero',
+ value: 0,
+ },
+ },
+ properties: [
+ {
+ id: 'custom.hideFrom',
+ value: {
+ legend: true,
+ tooltip: true,
+ viz: true,
+ },
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ legend: {
+ displayMode: 'list',
+ placement: 'bottom',
+ showLegend: true,
+ },
+ tooltip: {
+ mode: 'multi',
+ sort: 'desc',
+ },
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsForPeriodTable.tsx b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsForPeriodTable.tsx
new file mode 100644
index 00000000..b7c4d722
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsForPeriodTable.tsx
@@ -0,0 +1,113 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getNewAlertGroupsNotificationsForPeriodTableScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(increase(max_over_time(sum by (username) (avg without(pod, instance) ($user_was_notified_of_alert_groups_total{slug=~"$instance"}))[1h:])[$__range:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ username: false,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'Alert groups',
+ team: 'Team',
+ username: 'Username',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'New alert groups notifications for period',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ custom: {
+ align: 'auto',
+ cellOptions: {
+ type: 'gauge',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ decimals: 0,
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ unit: 'none',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Username',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsInTotal.tsx b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsInTotal.tsx
new file mode 100644
index 00000000..2e6564a6
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/NewAlertGroupsNotificationsInTotal.tsx
@@ -0,0 +1,113 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getNewAlertGroupsNotificationsInTotalScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ editorMode: 'code',
+ exemplar: false,
+ expr: 'sort_desc(max_over_time(sum by(username) (avg without(pod, instance)($user_was_notified_of_alert_groups_total{slug=~"$instance"}))[1d:]))',
+ format: 'table',
+ instant: true,
+ legendFormat: '__auto',
+ range: false,
+ refId: 'A',
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'seriesToRows',
+ options: {},
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {
+ Time: true,
+ username: false,
+ },
+ indexByName: {},
+ renameByName: {
+ Metric: 'Integration',
+ Value: 'Alert groups',
+ team: 'Team',
+ username: 'Username',
+ },
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'New alert groups notifications in total',
+ pluginId: 'table',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ custom: {
+ align: 'auto',
+ cellOptions: {
+ mode: 'gradient',
+ type: 'gauge',
+ valueDisplayMode: 'color',
+ },
+ filterable: false,
+ inspect: false,
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Username',
+ },
+ properties: [
+ {
+ id: 'custom.cellOptions',
+ value: {
+ type: 'auto',
+ },
+ },
+ {
+ id: 'custom.width',
+ value: 300,
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ cellHeight: 'sm',
+ footer: {
+ countRows: false,
+ fields: '',
+ reducer: ['sum'],
+ show: false,
+ },
+ showHeader: true,
+ },
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/TotalAlertGroups.tsx b/grafana-plugin/src/pages/insights/scenes/TotalAlertGroups.tsx
new file mode 100644
index 00000000..ebd3facd
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/TotalAlertGroups.tsx
@@ -0,0 +1,79 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getTotalAlertGroupsScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ disableTextWrap: false,
+ editorMode: 'code',
+ excludeNullMetadata: false,
+ exemplar: false,
+ expr: 'max_over_time(sum(avg without(pod, instance) ($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))[1d:])',
+ format: 'time_series',
+ fullMetaSearch: false,
+ instant: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ useBackend: false,
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: query,
+ body: new VizPanel({
+ pluginId: 'stat',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'text',
+ value: null,
+ },
+ ],
+ },
+ unit: 'none',
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'Value',
+ },
+ properties: [
+ {
+ id: 'displayName',
+ value: 'Total alert groups',
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ colorMode: 'value',
+ graphMode: 'none',
+ justifyMode: 'center',
+ orientation: 'auto',
+ reduceOptions: {
+ calcs: ['lastNotNull'],
+ fields: '',
+ values: false,
+ },
+ textMode: 'auto',
+ },
+ pluginVersion: '9.5.2',
+ title: 'Total alert groups',
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/scenes/TotalAlertGroupsByState.tsx b/grafana-plugin/src/pages/insights/scenes/TotalAlertGroupsByState.tsx
new file mode 100644
index 00000000..7d36795b
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/scenes/TotalAlertGroupsByState.tsx
@@ -0,0 +1,133 @@
+import { ThresholdsMode } from '@grafana/data';
+import { SceneDataTransformer, SceneFlexItem, SceneQueryRunner, VizPanel } from '@grafana/scenes';
+
+import { InsightsConfig } from 'pages/insights/Insights.types';
+
+export default function getTotalAlertGroupsByStateScene({ datasource }: InsightsConfig) {
+ const query = new SceneQueryRunner({
+ datasource,
+ queries: [
+ {
+ disableTextWrap: false,
+ editorMode: 'code',
+ excludeNullMetadata: false,
+ expr: 'sum by (state) (avg without(pod, instance) ($alert_groups_total{slug=~"$instance", team=~"$team", integration=~"$integration"}))',
+ fullMetaSearch: false,
+ legendFormat: '__auto',
+ range: true,
+ refId: 'A',
+ useBackend: false,
+ },
+ ],
+ });
+
+ const transformedData = new SceneDataTransformer({
+ $data: query,
+ transformations: [
+ {
+ id: 'joinByLabels',
+ options: {
+ value: 'state',
+ },
+ },
+ {
+ id: 'organize',
+ options: {
+ excludeByName: {},
+ indexByName: {
+ acknowledged: 1,
+ firing: 0,
+ resolved: 2,
+ silenced: 3,
+ },
+ renameByName: {},
+ },
+ },
+ ],
+ });
+
+ return new SceneFlexItem({
+ $data: transformedData,
+ body: new VizPanel({
+ title: 'Total alert groups by state',
+ pluginId: 'bargauge',
+ fieldConfig: {
+ defaults: {
+ color: {
+ mode: 'thresholds',
+ },
+ mappings: [],
+ thresholds: {
+ mode: ThresholdsMode.Absolute,
+ steps: [
+ {
+ color: 'green',
+ value: null,
+ },
+ ],
+ },
+ },
+ overrides: [
+ {
+ matcher: {
+ id: 'byName',
+ options: 'firing',
+ },
+ properties: [
+ {
+ id: 'color',
+ value: {
+ fixedColor: 'red',
+ mode: 'fixed',
+ },
+ },
+ ],
+ },
+ {
+ matcher: {
+ id: 'byName',
+ options: 'acknowledged',
+ },
+ properties: [
+ {
+ id: 'color',
+ value: {
+ fixedColor: 'dark-yellow',
+ mode: 'fixed',
+ },
+ },
+ ],
+ },
+ {
+ matcher: {
+ id: 'byName',
+ options: 'silenced',
+ },
+ properties: [
+ {
+ id: 'color',
+ value: {
+ mode: 'fixed',
+ },
+ },
+ ],
+ },
+ ],
+ },
+ options: {
+ displayMode: 'gradient',
+ minVizHeight: 10,
+ minVizWidth: 0,
+ orientation: 'vertical',
+ reduceOptions: {
+ calcs: ['lastNotNull'],
+ fields: '',
+ values: false,
+ },
+ showUnfilled: true,
+ valueMode: 'color',
+ },
+ pluginVersion: '9.5.2',
+ }),
+ });
+}
diff --git a/grafana-plugin/src/pages/insights/variables.ts b/grafana-plugin/src/pages/insights/variables.ts
new file mode 100644
index 00000000..1d121789
--- /dev/null
+++ b/grafana-plugin/src/pages/insights/variables.ts
@@ -0,0 +1,138 @@
+import { DataSourceVariable, QueryVariable } from '@grafana/scenes';
+
+import { InsightsConfig } from './Insights.types';
+
+const DEFAULT_VARIABLE_CONFIG: Partial
[0]> = {
+ hide: 0,
+ includeAll: true,
+ isMulti: true,
+ options: [],
+ refresh: 1,
+ regex: '',
+ skipUrlSync: false,
+ sort: 0,
+ type: 'query',
+};
+
+const getVariables = ({ isOpenSource, datasource }: InsightsConfig) => [
+ // Selectable
+ ...(isOpenSource
+ ? [
+ new DataSourceVariable({
+ name: 'datasource',
+ label: 'Data source',
+ pluginId: 'prometheus',
+ value: 'grafanacloud-usage',
+ }),
+ ]
+ : []),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'instance',
+ label: 'Instance',
+ text: ['All'],
+ value: ['$__all'],
+ datasource,
+ definition: 'label_values(${alert_groups_total},slug)',
+ query: {
+ query: 'label_values(${alert_groups_total},slug)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'team',
+ label: 'Team',
+ text: ['All'],
+ value: ['$__all'],
+ datasource,
+ definition: 'label_values(${alert_groups_total}{slug=~"$instance"},team)',
+ query: {
+ query: 'label_values(${alert_groups_total}{slug=~"$instance"},team)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ refresh: 2,
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'integration',
+ label: 'Integration',
+ text: ['All'],
+ value: ['$__all'],
+ datasource,
+ definition: 'label_values(${alert_groups_total}{team=~"$team",slug=~"$instance"},integration)',
+ query: {
+ query: 'label_values(${alert_groups_total}{team=~"$team",slug=~"$instance"},integration)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ refresh: 2,
+ }),
+
+ // Non-selectable
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'alert_groups_total',
+ label: 'alert_groups_total',
+ datasource,
+ query: {
+ query: 'metrics(alert_groups_total)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ text: ['oncall_alert_groups_total', 'grafanacloud_oncall_instance_alert_groups_total'],
+ value: ['oncall_alert_groups_total', 'grafanacloud_oncall_instance_alert_groups_total'],
+ definition: 'metrics(alert_groups_total)',
+ hide: 2,
+ includeAll: false,
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'user_was_notified_of_alert_groups_total',
+ label: 'user_was_notified_of_alert_groups_total',
+ datasource,
+ definition: 'metrics(user_was_notified_of_alert_groups_total)',
+ query: {
+ query: 'metrics(user_was_notified_of_alert_groups_total)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ hide: 2,
+ refresh: 2,
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'alert_groups_response_time_seconds_bucket',
+ label: 'alert_groups_response_time_seconds_bucket',
+ datasource,
+ definition: 'metrics(alert_groups_response_time_seconds_bucket)',
+ query: {
+ query: 'metrics(alert_groups_response_time_seconds_bucket)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ hide: 2,
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'alert_groups_response_time_seconds_sum',
+ label: 'alert_groups_response_time_seconds_sum',
+ datasource,
+ definition: 'metrics(alert_groups_response_time_seconds_sum)',
+ query: {
+ query: 'metrics(alert_groups_response_time_seconds_sum)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ hide: 2,
+ }),
+ new QueryVariable({
+ ...DEFAULT_VARIABLE_CONFIG,
+ name: 'alert_groups_response_time_seconds_count',
+ label: 'alert_groups_response_time_seconds_count',
+ datasource,
+ definition: 'metrics(alert_groups_response_time_seconds_count)',
+ query: {
+ query: 'metrics(alert_groups_response_time_seconds_count)',
+ refId: 'PrometheusVariableQueryEditor-VariableQuery',
+ },
+ hide: 2,
+ }),
+];
+
+export default getVariables;
diff --git a/grafana-plugin/src/pages/routes.tsx b/grafana-plugin/src/pages/routes.tsx
index a224529d..048c83ec 100644
--- a/grafana-plugin/src/pages/routes.tsx
+++ b/grafana-plugin/src/pages/routes.tsx
@@ -1,6 +1,7 @@
import EscalationsChainsPage from 'pages/escalation-chains/EscalationChains';
import IncidentPage from 'pages/incident/Incident';
import IncidentsPage from 'pages/incidents/Incidents';
+import Insights from 'pages/insights/Insights';
import OutgoingWebhooks from 'pages/outgoing_webhooks/OutgoingWebhooks';
import SchedulePage from 'pages/schedule/Schedule';
import SchedulesPage from 'pages/schedules/Schedules';
@@ -66,6 +67,10 @@ export const routes: { [id: string]: NavRoute } = [
component: CloudPage,
id: 'cloud',
},
+ {
+ component: Insights,
+ id: 'insights',
+ },
].reduce((prev, current) => {
prev[current.id] = {
id: current.id,
diff --git a/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx b/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx
index 824e9191..c4cb87b7 100644
--- a/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx
+++ b/grafana-plugin/src/pages/settings/tabs/ChatOps/ChatOps.tsx
@@ -47,7 +47,7 @@ class ChatOpsPage extends React.Component {
const { activeTab } = this.state;
const { store } = this.props;
- if (!this.isChatOpsConfigured() && store.isOpenSource()) {
+ if (!this.isChatOpsConfigured() && store.isOpenSource) {
return this.renderNoChatOpsBannerInfo();
}
diff --git a/grafana-plugin/src/plugin.json b/grafana-plugin/src/plugin.json
index 2dc75d5b..8fe77354 100644
--- a/grafana-plugin/src/plugin.json
+++ b/grafana-plugin/src/plugin.json
@@ -94,6 +94,14 @@
"action": "grafana-oncall-app.other-settings:read",
"addToNav": true
},
+ {
+ "type": "page",
+ "name": "Insights",
+ "path": "/a/grafana-oncall-app/insights",
+ "role": "Viewer",
+ "action": "grafana-oncall-app.other-settings:read",
+ "addToNav": true
+ },
{
"type": "dashboard",
"path": "dashboards/oncall_metrics_dashboard.json",
diff --git a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx
index ec89e331..8f87baaa 100644
--- a/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx
+++ b/grafana-plugin/src/plugin/GrafanaPluginRootPage.tsx
@@ -26,6 +26,7 @@ import NoMatch from 'pages/NoMatch';
import EscalationChains from 'pages/escalation-chains/EscalationChains';
import Incident from 'pages/incident/Incident';
import Incidents from 'pages/incidents/Incidents';
+import Insights from 'pages/insights/Insights';
import Integration from 'pages/integration/Integration';
import Integrations from 'pages/integrations/Integrations';
import OutgoingWebhooks from 'pages/outgoing_webhooks/OutgoingWebhooks';
@@ -181,6 +182,9 @@ export const Root = observer((props: AppRootProps) => {
+
+
+
{/* Backwards compatibility redirect routes */}