mirror of https://github.com/grafana/grafana
Alerting: Recognise & change UI for OnCall notification policy + contact point (#60259)
* Identify and show onCall contact points with a badge in case the plugin is installed * Add onCall logo for onCall contact points Badge * Refactor and make Grafana App Receiver type more generic, not only for onCall type * Show onCall notification policy in the specific routing table with special onCall badge * Fix tests * Move onCall badge to the type column in contact points view table * Fix typos and remove onCallIntegrations from tagTypes in alertingApi * Fetch only local plugins instead of all (external are not needed) and don't fetch plugin details * Use directly useGetOnCallIntegrationsQuery and more PR review suggestions * Move onCall contact point to the top in the drop-down, in the notification policy view * Add PR review requested changespull/60650/head
parent
c537d3699c
commit
e219e2a834
@ -0,0 +1,20 @@ |
||||
import { alertingApi } from './alertingApi'; |
||||
export interface OnCallIntegration { |
||||
integration_url: string; |
||||
} |
||||
export type OnCallIntegrationsResponse = OnCallIntegration[]; |
||||
export type OnCallIntegrationsUrls = string[]; |
||||
|
||||
export const onCallApi = alertingApi.injectEndpoints({ |
||||
endpoints: (build) => ({ |
||||
getOnCallIntegrations: build.query<OnCallIntegrationsUrls, void>({ |
||||
query: () => ({ |
||||
headers: {}, |
||||
url: '/api/plugin-proxy/grafana-oncall-app/api/internal/v1/alert_receive_channels/', |
||||
}), |
||||
providesTags: ['AlertmanagerChoice'], |
||||
transformResponse: (response: OnCallIntegrationsResponse) => response.map((result) => result.integration_url), |
||||
}), |
||||
}), |
||||
}); |
||||
export const { useGetOnCallIntegrationsQuery } = onCallApi; |
@ -0,0 +1,32 @@ |
||||
import { css } from '@emotion/css'; |
||||
import React from 'react'; |
||||
|
||||
import { GrafanaTheme2 } from '@grafana/data'; |
||||
import { HorizontalGroup, useStyles2 } from '@grafana/ui'; |
||||
|
||||
import { GRAFANA_APP_RECEIVERS_SOURCE_IMAGE, GrafanaAppReceiverEnum } from './types'; |
||||
|
||||
export const GrafanaAppBadge = ({ grafanaAppType }: { grafanaAppType: GrafanaAppReceiverEnum }) => { |
||||
const styles = useStyles2(getStyles); |
||||
return ( |
||||
<div className={styles.wrapper}> |
||||
<HorizontalGroup align="center" spacing="xs"> |
||||
<img src={GRAFANA_APP_RECEIVERS_SOURCE_IMAGE[grafanaAppType]} alt="" height="12px" /> |
||||
<span>{grafanaAppType}</span> |
||||
</HorizontalGroup> |
||||
</div> |
||||
); |
||||
}; |
||||
|
||||
const getStyles = (theme: GrafanaTheme2) => ({ |
||||
wrapper: css` |
||||
text-align: left; |
||||
height: 22px; |
||||
display: inline-flex; |
||||
padding: 1px 4px; |
||||
border-radius: 3px; |
||||
border: 1px solid rgba(245, 95, 62, 1); |
||||
color: rgba(245, 95, 62, 1); |
||||
font-weight: ${theme.typography.fontWeightRegular}; |
||||
`,
|
||||
}); |
@ -0,0 +1,56 @@ |
||||
import { useGetSingleLocalWithoutDetails } from 'app/features/plugins/admin/state/hooks'; |
||||
import { CatalogPlugin } from 'app/features/plugins/admin/types'; |
||||
import { Receiver } from 'app/plugins/datasource/alertmanager/types'; |
||||
|
||||
import { useGetOnCallIntegrationsQuery } from '../../../api/onCallApi'; |
||||
|
||||
import { isOnCallReceiver } from './onCall/onCall'; |
||||
import { AmRouteReceiver, GrafanaAppReceiverEnum, GRAFANA_APP_PLUGIN_IDS, ReceiverWithTypes } from './types'; |
||||
|
||||
export const useGetAppIsInstalledAndEnabled = (grafanaAppType: GrafanaAppReceiverEnum) => { |
||||
// fetches the plugin settings for this Grafana instance
|
||||
const plugin: CatalogPlugin | undefined = useGetSingleLocalWithoutDetails(GRAFANA_APP_PLUGIN_IDS[grafanaAppType]); |
||||
return plugin?.isInstalled && !plugin?.isDisabled && plugin?.type === 'app'; |
||||
}; |
||||
|
||||
export const useGetGrafanaReceiverTypeChecker = () => { |
||||
const isOnCallEnabled = useGetAppIsInstalledAndEnabled(GrafanaAppReceiverEnum.GRAFANA_ONCALL); |
||||
const { data } = useGetOnCallIntegrationsQuery(undefined, { |
||||
skip: !isOnCallEnabled, |
||||
}); |
||||
|
||||
const getGrafanaReceiverType = (receiver: Receiver): GrafanaAppReceiverEnum | undefined => { |
||||
//CHECK FOR ONCALL PLUGIN
|
||||
const onCallIntegrations = data ?? []; |
||||
if (isOnCallEnabled && isOnCallReceiver(receiver, onCallIntegrations)) { |
||||
return GrafanaAppReceiverEnum.GRAFANA_ONCALL; |
||||
} |
||||
//WE WILL ADD IN HERE IF THERE ARE MORE TYPES TO CHECK
|
||||
return undefined; |
||||
}; |
||||
return getGrafanaReceiverType; |
||||
}; |
||||
|
||||
export const useGetAmRouteReceiverWithGrafanaAppTypes = (receivers: Receiver[]) => { |
||||
const getGrafanaReceiverType = useGetGrafanaReceiverTypeChecker(); |
||||
const receiverToSelectableContactPointValue = (receiver: Receiver): AmRouteReceiver => { |
||||
const amRouteReceiverValue: AmRouteReceiver = { |
||||
label: receiver.name, |
||||
value: receiver.name, |
||||
grafanaAppReceiverType: getGrafanaReceiverType(receiver), |
||||
}; |
||||
return amRouteReceiverValue; |
||||
}; |
||||
|
||||
return receivers.map(receiverToSelectableContactPointValue); |
||||
}; |
||||
|
||||
export const useGetReceiversWithGrafanaAppTypes = (receivers: Receiver[]): ReceiverWithTypes[] => { |
||||
const getGrafanaReceiverType = useGetGrafanaReceiverTypeChecker(); |
||||
return receivers.map((receiver: Receiver) => { |
||||
return { |
||||
...receiver, |
||||
grafanaAppReceiverType: getGrafanaReceiverType(receiver), |
||||
}; |
||||
}); |
||||
}; |
@ -0,0 +1,19 @@ |
||||
import { Receiver } from 'app/plugins/datasource/alertmanager/types'; |
||||
|
||||
export const isInOnCallIntegrations = (url: string, integrationsUrls: string[]) => { |
||||
return integrationsUrls.includes(url); |
||||
}; |
||||
|
||||
export const isOnCallReceiver = (receiver: Receiver, integrationsUrls: string[]) => { |
||||
if (!receiver.grafana_managed_receiver_configs) { |
||||
return false; |
||||
} |
||||
// A receiver it's an onCall contact point if it includes only one integration, and this integration it's an onCall
|
||||
// An integration it's an onCall type if it's included in the list of integrations returned by the onCall api endpoint
|
||||
const onlyOneIntegration = receiver.grafana_managed_receiver_configs.length === 1; |
||||
const isOncall = isInOnCallIntegrations( |
||||
receiver.grafana_managed_receiver_configs[0]?.settings?.url ?? '', |
||||
integrationsUrls |
||||
); |
||||
return onlyOneIntegration && isOncall; |
||||
}; |
@ -0,0 +1,23 @@ |
||||
import { Receiver } from '../../../../../../plugins/datasource/alertmanager/types'; |
||||
// we will add in here more types if needed
|
||||
export enum GrafanaAppReceiverEnum { |
||||
GRAFANA_ONCALL = 'Grafana OnCall', |
||||
} |
||||
|
||||
export interface AmRouteReceiver { |
||||
label: string; |
||||
value: string; |
||||
grafanaAppReceiverType?: GrafanaAppReceiverEnum; |
||||
} |
||||
|
||||
export interface ReceiverWithTypes extends Receiver { |
||||
grafanaAppReceiverType?: GrafanaAppReceiverEnum; |
||||
} |
||||
|
||||
export const GRAFANA_APP_RECEIVERS_SOURCE_IMAGE = { |
||||
'Grafana OnCall': 'public/img/alerting/oncall_logo.svg', |
||||
}; |
||||
|
||||
export enum GRAFANA_APP_PLUGIN_IDS { |
||||
'Grafana OnCall' = 'grafana-oncall-app', |
||||
} |
After Width: | Height: | Size: 2.4 KiB |
Loading…
Reference in new issue