mirror of
https://github.com/grafana/grafana.git
synced 2025-02-25 18:55:37 -06:00
Alerting: use SupportedPlugin.OnCall detecting OnCall types as a single source of truth (#61473)
Use SupportedPlugin.OnCall detecting OnCall types as a single source of truth
This commit is contained in:
@@ -3,7 +3,7 @@ import { setupServer } from 'msw/node';
|
|||||||
|
|
||||||
// bit of setup to mock HTTP request responses
|
// bit of setup to mock HTTP request responses
|
||||||
import 'whatwg-fetch';
|
import 'whatwg-fetch';
|
||||||
import { SupportedPlugin } from './PluginBridge';
|
import { SupportedPlugin } from '../types/pluginBridges';
|
||||||
|
|
||||||
export const NON_EXISTING_PLUGIN = '__does_not_exist__';
|
export const NON_EXISTING_PLUGIN = '__does_not_exist__';
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,9 @@ import React from 'react';
|
|||||||
import { setBackendSrv } from '@grafana/runtime';
|
import { setBackendSrv } from '@grafana/runtime';
|
||||||
import { backendSrv } from 'app/core/services/backend_srv';
|
import { backendSrv } from 'app/core/services/backend_srv';
|
||||||
|
|
||||||
import { createBridgeURL, PluginBridge, SupportedPlugin } from './PluginBridge';
|
import { SupportedPlugin } from '../types/pluginBridges';
|
||||||
|
|
||||||
|
import { createBridgeURL, PluginBridge } from './PluginBridge';
|
||||||
import { server, NON_EXISTING_PLUGIN } from './PluginBridge.mock';
|
import { server, NON_EXISTING_PLUGIN } from './PluginBridge.mock';
|
||||||
|
|
||||||
beforeAll(() => {
|
beforeAll(() => {
|
||||||
|
|||||||
@@ -1,14 +1,7 @@
|
|||||||
import React, { FC, ReactElement } from 'react';
|
import React, { FC, ReactElement } from 'react';
|
||||||
import { useAsync } from 'react-use';
|
|
||||||
|
|
||||||
import { PluginMeta } from '@grafana/data';
|
import { usePluginBridge } from '../hooks/usePluginBridge';
|
||||||
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
|
import { SupportedPlugin } from '../types/pluginBridges';
|
||||||
|
|
||||||
export enum SupportedPlugin {
|
|
||||||
Incident = 'grafana-incident-app',
|
|
||||||
OnCall = 'grafana-oncall-app',
|
|
||||||
MachineLearning = 'grafana-ml-app',
|
|
||||||
}
|
|
||||||
|
|
||||||
export type PluginID = SupportedPlugin | string;
|
export type PluginID = SupportedPlugin | string;
|
||||||
|
|
||||||
@@ -20,13 +13,6 @@ export interface PluginBridgeProps {
|
|||||||
loadingComponent?: ReactElement;
|
loadingComponent?: ReactElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface PluginBridgeHookResponse {
|
|
||||||
loading: boolean;
|
|
||||||
installed?: boolean;
|
|
||||||
error?: Error;
|
|
||||||
settings?: PluginMeta<{}>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const PluginBridge: FC<PluginBridgeProps> = ({ children, plugin, loadingComponent, notInstalledFallback }) => {
|
export const PluginBridge: FC<PluginBridgeProps> = ({ children, plugin, loadingComponent, notInstalledFallback }) => {
|
||||||
const { loading, installed } = usePluginBridge(plugin);
|
const { loading, installed } = usePluginBridge(plugin);
|
||||||
|
|
||||||
@@ -41,24 +27,6 @@ export const PluginBridge: FC<PluginBridgeProps> = ({ children, plugin, loadingC
|
|||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export function usePluginBridge(plugin: PluginID): PluginBridgeHookResponse {
|
|
||||||
const { loading, error, value } = useAsync(() => getPluginSettings(plugin, { showErrorAlert: false }));
|
|
||||||
|
|
||||||
const installed = value && !error && !loading;
|
|
||||||
const enabled = value?.enabled;
|
|
||||||
const isLoading = loading && !value;
|
|
||||||
|
|
||||||
if (isLoading) {
|
|
||||||
return { loading: true };
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!installed || !enabled) {
|
|
||||||
return { loading: false, installed: false };
|
|
||||||
}
|
|
||||||
|
|
||||||
return { loading, installed: true, settings: value };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function createBridgeURL(plugin: PluginID, path?: string, options?: Record<string, string>) {
|
export function createBridgeURL(plugin: PluginID, path?: string, options?: Record<string, string>) {
|
||||||
const searchParams = new URLSearchParams(options).toString();
|
const searchParams = new URLSearchParams(options).toString();
|
||||||
const pluginPath = `/a/${plugin}${path}`;
|
const pluginPath = `/a/${plugin}${path}`;
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import {
|
|||||||
|
|
||||||
import { useMuteTimingOptions } from '../../hooks/useMuteTimingOptions';
|
import { useMuteTimingOptions } from '../../hooks/useMuteTimingOptions';
|
||||||
import { FormAmRoute } from '../../types/amroutes';
|
import { FormAmRoute } from '../../types/amroutes';
|
||||||
|
import { SupportedPlugin } from '../../types/pluginBridges';
|
||||||
import { matcherFieldOptions } from '../../utils/alertmanager';
|
import { matcherFieldOptions } from '../../utils/alertmanager';
|
||||||
import {
|
import {
|
||||||
emptyArrayFieldMatcher,
|
emptyArrayFieldMatcher,
|
||||||
@@ -32,7 +33,7 @@ import {
|
|||||||
commonGroupByOptions,
|
commonGroupByOptions,
|
||||||
} from '../../utils/amroutes';
|
} from '../../utils/amroutes';
|
||||||
import { timeOptions } from '../../utils/time';
|
import { timeOptions } from '../../utils/time';
|
||||||
import { AmRouteReceiver, GrafanaAppReceiverEnum } from '../receivers/grafanaAppReceivers/types';
|
import { AmRouteReceiver } from '../receivers/grafanaAppReceivers/types';
|
||||||
|
|
||||||
import { getFormStyles } from './formStyles';
|
import { getFormStyles } from './formStyles';
|
||||||
|
|
||||||
@@ -50,7 +51,7 @@ export const AmRoutesExpandedForm: FC<AmRoutesExpandedFormProps> = ({ onCancel,
|
|||||||
const muteTimingOptions = useMuteTimingOptions();
|
const muteTimingOptions = useMuteTimingOptions();
|
||||||
|
|
||||||
const receiversWithOnCallOnTop = receivers.sort((receiver1, receiver2) => {
|
const receiversWithOnCallOnTop = receivers.sort((receiver1, receiver2) => {
|
||||||
if (receiver1.grafanaAppReceiverType === GrafanaAppReceiverEnum.GRAFANA_ONCALL) {
|
if (receiver1.grafanaAppReceiverType === SupportedPlugin.OnCall) {
|
||||||
return -1;
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
@@ -2,7 +2,9 @@ import React, { FC } from 'react';
|
|||||||
|
|
||||||
import { Button, LinkButton, Tooltip } from '@grafana/ui';
|
import { Button, LinkButton, Tooltip } from '@grafana/ui';
|
||||||
|
|
||||||
import { createBridgeURL, usePluginBridge, SupportedPlugin } from '../PluginBridge';
|
import { usePluginBridge } from '../../hooks/usePluginBridge';
|
||||||
|
import { SupportedPlugin } from '../../types/pluginBridges';
|
||||||
|
import { createBridgeURL } from '../PluginBridge';
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
title?: string;
|
title?: string;
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import { Authorize } from '../../components/Authorize';
|
|||||||
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
import { useUnifiedAlertingSelector } from '../../hooks/useUnifiedAlertingSelector';
|
||||||
import { deleteReceiverAction } from '../../state/actions';
|
import { deleteReceiverAction } from '../../state/actions';
|
||||||
import { getAlertTableStyles } from '../../styles/table';
|
import { getAlertTableStyles } from '../../styles/table';
|
||||||
|
import { SupportedPlugin } from '../../types/pluginBridges';
|
||||||
import { getNotificationsPermissions } from '../../utils/access-control';
|
import { getNotificationsPermissions } from '../../utils/access-control';
|
||||||
import { isReceiverUsed } from '../../utils/alertmanager';
|
import { isReceiverUsed } from '../../utils/alertmanager';
|
||||||
import { isVanillaPrometheusAlertManagerDataSource } from '../../utils/datasource';
|
import { isVanillaPrometheusAlertManagerDataSource } from '../../utils/datasource';
|
||||||
@@ -26,7 +27,7 @@ import { ActionIcon } from '../rules/ActionIcon';
|
|||||||
import { ReceiversSection } from './ReceiversSection';
|
import { ReceiversSection } from './ReceiversSection';
|
||||||
import { GrafanaAppBadge } from './grafanaAppReceivers/GrafanaAppBadge';
|
import { GrafanaAppBadge } from './grafanaAppReceivers/GrafanaAppBadge';
|
||||||
import { useGetReceiversWithGrafanaAppTypes } from './grafanaAppReceivers/grafanaApp';
|
import { useGetReceiversWithGrafanaAppTypes } from './grafanaAppReceivers/grafanaApp';
|
||||||
import { GrafanaAppReceiverEnum, ReceiverWithTypes } from './grafanaAppReceivers/types';
|
import { ReceiverWithTypes } from './grafanaAppReceivers/types';
|
||||||
|
|
||||||
interface UpdateActionProps extends ActionProps {
|
interface UpdateActionProps extends ActionProps {
|
||||||
onClickDeleteReceiver: (receiverName: string) => void;
|
onClickDeleteReceiver: (receiverName: string) => void;
|
||||||
@@ -131,7 +132,7 @@ interface ReceiverItem {
|
|||||||
name: string;
|
name: string;
|
||||||
types: string[];
|
types: string[];
|
||||||
provisioned?: boolean;
|
provisioned?: boolean;
|
||||||
grafanaAppReceiverType?: GrafanaAppReceiverEnum;
|
grafanaAppReceiverType?: SupportedPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface NotifierStatus {
|
interface NotifierStatus {
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import React from 'react';
|
|||||||
import { GrafanaTheme2 } from '@grafana/data';
|
import { GrafanaTheme2 } from '@grafana/data';
|
||||||
import { HorizontalGroup, useStyles2 } from '@grafana/ui';
|
import { HorizontalGroup, useStyles2 } from '@grafana/ui';
|
||||||
|
|
||||||
import { GRAFANA_APP_RECEIVERS_SOURCE_IMAGE, GrafanaAppReceiverEnum } from './types';
|
import { SupportedPlugin } from '../../../types/pluginBridges';
|
||||||
|
|
||||||
export const GrafanaAppBadge = ({ grafanaAppType }: { grafanaAppType: GrafanaAppReceiverEnum }) => {
|
import { GRAFANA_APP_RECEIVERS_SOURCE_IMAGE } from './types';
|
||||||
|
|
||||||
|
export const GrafanaAppBadge = ({ grafanaAppType }: { grafanaAppType: SupportedPlugin }) => {
|
||||||
const styles = useStyles2(getStyles);
|
const styles = useStyles2(getStyles);
|
||||||
return (
|
return (
|
||||||
<div className={styles.wrapper}>
|
<div className={styles.wrapper}>
|
||||||
|
|||||||
@@ -1,21 +1,22 @@
|
|||||||
import { Receiver } from 'app/plugins/datasource/alertmanager/types';
|
import { Receiver } from 'app/plugins/datasource/alertmanager/types';
|
||||||
|
|
||||||
import { useGetOnCallIntegrationsQuery } from '../../../api/onCallApi';
|
import { useGetOnCallIntegrationsQuery } from '../../../api/onCallApi';
|
||||||
import { SupportedPlugin, usePluginBridge } from '../../PluginBridge';
|
import { usePluginBridge } from '../../../hooks/usePluginBridge';
|
||||||
|
import { SupportedPlugin } from '../../../types/pluginBridges';
|
||||||
|
|
||||||
import { isOnCallReceiver } from './onCall/onCall';
|
import { isOnCallReceiver } from './onCall/onCall';
|
||||||
import { AmRouteReceiver, GrafanaAppReceiverEnum, ReceiverWithTypes } from './types';
|
import { AmRouteReceiver, ReceiverWithTypes } from './types';
|
||||||
|
|
||||||
export const useGetGrafanaReceiverTypeChecker = () => {
|
export const useGetGrafanaReceiverTypeChecker = () => {
|
||||||
const { installed: isOnCallEnabled } = usePluginBridge(SupportedPlugin.OnCall);
|
const { installed: isOnCallEnabled } = usePluginBridge(SupportedPlugin.OnCall);
|
||||||
const { data } = useGetOnCallIntegrationsQuery(undefined, {
|
const { data } = useGetOnCallIntegrationsQuery(undefined, {
|
||||||
skip: !isOnCallEnabled,
|
skip: !isOnCallEnabled,
|
||||||
});
|
});
|
||||||
const getGrafanaReceiverType = (receiver: Receiver): GrafanaAppReceiverEnum | undefined => {
|
const getGrafanaReceiverType = (receiver: Receiver): SupportedPlugin | undefined => {
|
||||||
//CHECK FOR ONCALL PLUGIN
|
//CHECK FOR ONCALL PLUGIN
|
||||||
const onCallIntegrations = data ?? [];
|
const onCallIntegrations = data ?? [];
|
||||||
if (isOnCallEnabled && isOnCallReceiver(receiver, onCallIntegrations)) {
|
if (isOnCallEnabled && isOnCallReceiver(receiver, onCallIntegrations)) {
|
||||||
return GrafanaAppReceiverEnum.GRAFANA_ONCALL;
|
return SupportedPlugin.OnCall;
|
||||||
}
|
}
|
||||||
//WE WILL ADD IN HERE IF THERE ARE MORE TYPES TO CHECK
|
//WE WILL ADD IN HERE IF THERE ARE MORE TYPES TO CHECK
|
||||||
return undefined;
|
return undefined;
|
||||||
|
|||||||
@@ -1,23 +1,18 @@
|
|||||||
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
|
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types';
|
||||||
// we will add in here more types if needed
|
import { SupportedPlugin } from '../../../types/pluginBridges';
|
||||||
export enum GrafanaAppReceiverEnum {
|
|
||||||
GRAFANA_ONCALL = 'Grafana OnCall',
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface AmRouteReceiver {
|
export interface AmRouteReceiver {
|
||||||
label: string;
|
label: string;
|
||||||
value: string;
|
value: string;
|
||||||
grafanaAppReceiverType?: GrafanaAppReceiverEnum;
|
grafanaAppReceiverType?: SupportedPlugin;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ReceiverWithTypes extends Receiver {
|
export interface ReceiverWithTypes extends Receiver {
|
||||||
grafanaAppReceiverType?: GrafanaAppReceiverEnum;
|
grafanaAppReceiverType?: SupportedPlugin;
|
||||||
}
|
}
|
||||||
|
export const GRAFANA_APP_RECEIVERS_SOURCE_IMAGE: Record<SupportedPlugin, string> = {
|
||||||
|
[SupportedPlugin.OnCall]: 'public/img/alerting/oncall_logo.svg',
|
||||||
|
|
||||||
export const GRAFANA_APP_RECEIVERS_SOURCE_IMAGE = {
|
[SupportedPlugin.Incident]: '',
|
||||||
'Grafana OnCall': 'public/img/alerting/oncall_logo.svg',
|
[SupportedPlugin.MachineLearning]: '',
|
||||||
};
|
};
|
||||||
|
|
||||||
export enum GRAFANA_APP_PLUGIN_IDS {
|
|
||||||
'Grafana OnCall' = 'grafana-oncall-app',
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { useAsync } from 'react-use';
|
||||||
|
|
||||||
|
import { PluginMeta } from '@grafana/data';
|
||||||
|
import { getPluginSettings } from 'app/features/plugins/pluginSettings';
|
||||||
|
|
||||||
|
import { PluginID } from '../components/PluginBridge';
|
||||||
|
interface PluginBridgeHookResponse {
|
||||||
|
loading: boolean;
|
||||||
|
installed?: boolean;
|
||||||
|
error?: Error;
|
||||||
|
settings?: PluginMeta<{}>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function usePluginBridge(plugin: PluginID): PluginBridgeHookResponse {
|
||||||
|
const { loading, error, value } = useAsync(() => getPluginSettings(plugin, { showErrorAlert: false }));
|
||||||
|
|
||||||
|
const installed = value && !error && !loading;
|
||||||
|
const enabled = value?.enabled;
|
||||||
|
const isLoading = loading && !value;
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
return { loading: true };
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!installed || !enabled) {
|
||||||
|
return { loading: false, installed: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { loading, installed: true, settings: value };
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export enum SupportedPlugin {
|
||||||
|
Incident = 'grafana-incident-app',
|
||||||
|
OnCall = 'grafana-oncall-app',
|
||||||
|
MachineLearning = 'grafana-ml-app',
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user