View File Name : AlertSilences.4ff252ad4c0057124d5d.js.map
\n );\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n searchInput: css`\n width: 360px;\n `,\n flexRow: css`\n display: flex;\n flex-direction: row;\n align-items: flex-end;\n padding-bottom: ${theme.spacing(3)};\n border-bottom: 1px solid ${theme.colors.border.medium};\n `,\n rowChild: css`\n margin-right: ${theme.spacing(1)};\n margin-bottom: 0;\n max-height: 52px;\n `,\n fieldLabel: css`\n font-size: 12px;\n font-weight: 500;\n `,\n});\n","import { css } from '@emotion/css';\nimport React, { useMemo } from 'react';\n\nimport { dateMath, GrafanaTheme2 } from '@grafana/data';\nimport { CollapsableSection, Icon, Link, LinkButton, useStyles2, Stack } from '@grafana/ui';\nimport { useQueryParams } from 'app/core/hooks/useQueryParams';\nimport { AlertmanagerAlert, Silence, SilenceState } from 'app/plugins/datasource/alertmanager/types';\nimport { useDispatch } from 'app/types';\n\nimport { AlertmanagerAction, useAlertmanagerAbility } from '../../hooks/useAbilities';\nimport { expireSilenceAction } from '../../state/actions';\nimport { parseMatchers } from '../../utils/alertmanager';\nimport { getSilenceFiltersFromUrlParams, makeAMLink } from '../../utils/misc';\nimport { Authorize } from '../Authorize';\nimport { DynamicTable, DynamicTableColumnProps, DynamicTableItemProps } from '../DynamicTable';\nimport { ActionButton } from '../rules/ActionButton';\nimport { ActionIcon } from '../rules/ActionIcon';\n\nimport { Matchers } from './Matchers';\nimport { NoSilencesSplash } from './NoSilencesCTA';\nimport { SilenceDetails } from './SilenceDetails';\nimport { SilenceStateTag } from './SilenceStateTag';\nimport { SilencesFilter } from './SilencesFilter';\n\nexport interface SilenceTableItem extends Silence {\n silencedAlerts: AlertmanagerAlert[];\n}\n\ntype SilenceTableColumnProps = DynamicTableColumnProps
;\ntype SilenceTableItemProps = DynamicTableItemProps;\ninterface Props {\n silences: Silence[];\n alertManagerAlerts: AlertmanagerAlert[];\n alertManagerSourceName: string;\n}\n\nconst SilencesTable = ({ silences, alertManagerAlerts, alertManagerSourceName }: Props) => {\n const styles = useStyles2(getStyles);\n const [queryParams] = useQueryParams();\n const filteredSilencesNotExpired = useFilteredSilences(silences, false);\n const filteredSilencesExpired = useFilteredSilences(silences, true);\n\n const { silenceState: silenceStateInParams } = getSilenceFiltersFromUrlParams(queryParams);\n const showExpiredFromUrl = silenceStateInParams === SilenceState.Expired;\n\n const itemsNotExpired = useMemo((): SilenceTableItemProps[] => {\n const findSilencedAlerts = (id: string) => {\n return alertManagerAlerts.filter((alert) => alert.status.silencedBy.includes(id));\n };\n return filteredSilencesNotExpired.map((silence) => {\n const silencedAlerts = findSilencedAlerts(silence.id);\n return {\n id: silence.id,\n data: { ...silence, silencedAlerts },\n };\n });\n }, [filteredSilencesNotExpired, alertManagerAlerts]);\n\n const itemsExpired = useMemo((): SilenceTableItemProps[] => {\n const findSilencedAlerts = (id: string) => {\n return alertManagerAlerts.filter((alert) => alert.status.silencedBy.includes(id));\n };\n return filteredSilencesExpired.map((silence) => {\n const silencedAlerts = findSilencedAlerts(silence.id);\n return {\n id: silence.id,\n data: { ...silence, silencedAlerts },\n };\n });\n }, [filteredSilencesExpired, alertManagerAlerts]);\n\n return (\n \n {!!silences.length && (\n
\n \n \n \n \n Add Silence\n \n
\n \n \n {itemsExpired.length > 0 && (\n \n \n \n Expired silences are automatically deleted after 5 days. \n
\n \n \n )}\n \n )}\n {!silences.length &&
}\n
\n );\n};\n\nfunction SilenceList({\n items,\n alertManagerSourceName,\n dataTestId,\n}: {\n items: SilenceTableItemProps[];\n alertManagerSourceName: string;\n dataTestId: string;\n}) {\n const columns = useColumns(alertManagerSourceName);\n if (!!items.length) {\n return (\n }\n />\n );\n } else {\n return <>No matching silences found>;\n }\n}\n\nconst useFilteredSilences = (silences: Silence[], expired = false) => {\n const [queryParams] = useQueryParams();\n return useMemo(() => {\n const { queryString } = getSilenceFiltersFromUrlParams(queryParams);\n const silenceIdsString = queryParams?.silenceIds;\n return silences.filter((silence) => {\n if (typeof silenceIdsString === 'string') {\n const idsIncluded = silenceIdsString.split(',').includes(silence.id);\n if (!idsIncluded) {\n return false;\n }\n }\n if (queryString) {\n const matchers = parseMatchers(queryString);\n const matchersMatch = matchers.every((matcher) =>\n silence.matchers?.some(\n ({ name, value, isEqual, isRegex }) =>\n matcher.name === name &&\n matcher.value === value &&\n matcher.isEqual === isEqual &&\n matcher.isRegex === isRegex\n )\n );\n if (!matchersMatch) {\n return false;\n }\n }\n if (expired) {\n return silence.status.state === SilenceState.Expired;\n } else {\n return silence.status.state !== SilenceState.Expired;\n }\n });\n }, [queryParams, silences, expired]);\n};\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n topButtonContainer: css`\n display: flex;\n flex-direction: row;\n justify-content: flex-end;\n `,\n addNewSilence: css`\n margin: ${theme.spacing(2, 0)};\n `,\n callout: css`\n background-color: ${theme.colors.background.secondary};\n border-top: 3px solid ${theme.colors.info.border};\n border-radius: ${theme.shape.radius.default};\n height: 62px;\n display: flex;\n flex-direction: row;\n align-items: center;\n\n & > * {\n margin-left: ${theme.spacing(1)};\n }\n `,\n calloutIcon: css`\n color: ${theme.colors.info.text};\n `,\n editButton: css`\n margin-left: ${theme.spacing(0.5)};\n `,\n});\n\nfunction useColumns(alertManagerSourceName: string) {\n const dispatch = useDispatch();\n const styles = useStyles2(getStyles);\n const [updateSupported, updateAllowed] = useAlertmanagerAbility(AlertmanagerAction.UpdateSilence);\n\n return useMemo((): SilenceTableColumnProps[] => {\n const handleExpireSilenceClick = (id: string) => {\n dispatch(expireSilenceAction(alertManagerSourceName, id));\n };\n const columns: SilenceTableColumnProps[] = [\n {\n id: 'state',\n label: 'State',\n renderCell: function renderStateTag({ data: { status } }) {\n return ;\n },\n size: 4,\n },\n {\n id: 'matchers',\n label: 'Matching labels',\n renderCell: function renderMatchers({ data: { matchers } }) {\n return ;\n },\n size: 10,\n },\n {\n id: 'alerts',\n label: 'Alerts',\n renderCell: function renderSilencedAlerts({ data: { silencedAlerts } }) {\n return {silencedAlerts.length} ;\n },\n size: 4,\n },\n {\n id: 'schedule',\n label: 'Schedule',\n renderCell: function renderSchedule({ data: { startsAt, endsAt } }) {\n const startsAtDate = dateMath.parse(startsAt);\n const endsAtDate = dateMath.parse(endsAt);\n const dateDisplayFormat = 'YYYY-MM-DD HH:mm';\n return (\n <>\n {' '}\n {startsAtDate?.format(dateDisplayFormat)} {'-'}\n {endsAtDate?.format(dateDisplayFormat)}\n >\n );\n },\n size: 7,\n },\n ];\n if (updateSupported && updateAllowed) {\n columns.push({\n id: 'actions',\n label: 'Actions',\n renderCell: function renderActions({ data: silence }) {\n return (\n \n {silence.status.state === 'expired' ? (\n \n Recreate \n \n ) : (\n handleExpireSilenceClick(silence.id)}>\n Unsilence\n \n )}\n {silence.status.state !== 'expired' && (\n \n )}\n \n );\n },\n size: 5,\n });\n }\n return columns;\n }, [alertManagerSourceName, dispatch, styles.editButton, updateAllowed, updateSupported]);\n}\nexport default SilencesTable;\n","import { useEffect, useState } from 'react';\nimport { useRouteMatch } from 'react-router-dom';\n\nimport { NavModelItem } from '@grafana/data';\n\nconst defaultPageNav: Partial = {\n icon: 'bell-slash',\n};\n\nexport function useSilenceNavData() {\n const { isExact, path } = useRouteMatch();\n const [pageNav, setPageNav] = useState | undefined>();\n\n useEffect(() => {\n if (path === '/alerting/silence/new') {\n setPageNav({\n ...defaultPageNav,\n id: 'silence-new',\n text: 'Add silence',\n });\n } else if (path === '/alerting/silence/:id/edit') {\n setPageNav({\n ...defaultPageNav,\n id: 'silence-edit',\n text: 'Edit silence',\n });\n }\n }, [path, isExact]);\n\n return pageNav;\n}\n","import React, { useCallback, useEffect } from 'react';\nimport { Route, RouteChildrenProps, Switch } from 'react-router-dom';\n\nimport { Alert, withErrorBoundary } from '@grafana/ui';\nimport { Silence } from 'app/plugins/datasource/alertmanager/types';\nimport { useDispatch } from 'app/types';\n\nimport { featureDiscoveryApi } from './api/featureDiscoveryApi';\nimport { AlertmanagerPageWrapper } from './components/AlertingPageWrapper';\nimport { GrafanaAlertmanagerDeliveryWarning } from './components/GrafanaAlertmanagerDeliveryWarning';\nimport SilencesEditor from './components/silences/SilencesEditor';\nimport SilencesTable from './components/silences/SilencesTable';\nimport { useSilenceNavData } from './hooks/useSilenceNavData';\nimport { useUnifiedAlertingSelector } from './hooks/useUnifiedAlertingSelector';\nimport { useAlertmanager } from './state/AlertmanagerContext';\nimport { fetchAmAlertsAction, fetchSilencesAction } from './state/actions';\nimport { SILENCES_POLL_INTERVAL_MS } from './utils/constants';\nimport { AsyncRequestState, initialAsyncRequestState } from './utils/redux';\n\nconst Silences = () => {\n const { selectedAlertmanager } = useAlertmanager();\n\n const dispatch = useDispatch();\n const silences = useUnifiedAlertingSelector((state) => state.silences);\n const alertsRequests = useUnifiedAlertingSelector((state) => state.amAlerts);\n const alertsRequest = selectedAlertmanager\n ? alertsRequests[selectedAlertmanager] || initialAsyncRequestState\n : undefined;\n\n const { currentData: amFeatures } = featureDiscoveryApi.useDiscoverAmFeaturesQuery(\n { amSourceName: selectedAlertmanager ?? '' },\n { skip: !selectedAlertmanager }\n );\n\n useEffect(() => {\n function fetchAll() {\n if (selectedAlertmanager) {\n dispatch(fetchSilencesAction(selectedAlertmanager));\n dispatch(fetchAmAlertsAction(selectedAlertmanager));\n }\n }\n fetchAll();\n const interval = setInterval(() => fetchAll, SILENCES_POLL_INTERVAL_MS);\n return () => {\n clearInterval(interval);\n };\n }, [selectedAlertmanager, dispatch]);\n\n const { result, loading, error }: AsyncRequestState =\n (selectedAlertmanager && silences[selectedAlertmanager]) || initialAsyncRequestState;\n\n const getSilenceById = useCallback((id: string) => result && result.find((silence) => silence.id === id), [result]);\n\n const mimirLazyInitError =\n error?.message?.includes('the Alertmanager is not configured') && amFeatures?.lazyConfigInit;\n\n if (!selectedAlertmanager) {\n return null;\n }\n\n return (\n <>\n \n\n {mimirLazyInitError && (\n \n Create a new contact point to create a configuration using the default values or contact your administrator to\n set up the Alertmanager.\n \n )}\n {error && !loading && !mimirLazyInitError && (\n \n {error.message || 'Unknown error.'}\n \n )}\n {alertsRequest?.error && !alertsRequest?.loading && !mimirLazyInitError && (\n \n {alertsRequest.error?.message || 'Unknown error.'}\n \n )}\n {result && !error && (\n \n \n \n \n \n \n \n \n {({ match }: RouteChildrenProps<{ id: string }>) => {\n return (\n match?.params.id && (\n \n )\n );\n }}\n \n \n )}\n >\n );\n};\n\nfunction SilencesPage() {\n const pageNav = useSilenceNavData();\n\n return (\n \n \n \n );\n}\n\nexport default withErrorBoundary(SilencesPage, { style: 'page' });\n","import { chain, filter } from 'lodash';\nimport React, { PropsWithChildren } from 'react';\n\nimport {\n Abilities,\n Action,\n AlertingAction,\n AlertmanagerAction,\n useAlertingAbilities,\n useAllAlertmanagerAbilities,\n} from '../hooks/useAbilities';\n\ninterface AuthorizeProps extends PropsWithChildren {\n actions: AlertmanagerAction[] | AlertingAction[];\n}\n\nexport const Authorize = ({ actions, children }: AuthorizeProps) => {\n const alertmanagerActions = filter(actions, isAlertmanagerAction) as AlertmanagerAction[];\n const alertSourceActions = filter(actions, isAlertingAction) as AlertingAction[];\n\n if (alertmanagerActions.length) {\n return {children} ;\n }\n\n if (alertSourceActions.length) {\n return {children} ;\n }\n\n return null;\n};\n\ninterface ActionsProps extends PropsWithChildren {\n actions: T[];\n}\n\nconst AuthorizeAlertmanager = ({ actions, children }: ActionsProps) => {\n const alertmanagerAbilties = useAllAlertmanagerAbilities();\n const allowed = actionsAllowed(alertmanagerAbilties, actions);\n\n if (allowed) {\n return <>{children}>;\n } else {\n return null;\n }\n};\n\nconst AuthorizeAlertsource = ({ actions, children }: ActionsProps) => {\n const alertSourceAbilities = useAlertingAbilities();\n const allowed = actionsAllowed(alertSourceAbilities, actions);\n\n if (allowed) {\n return <>{children}>;\n } else {\n return null;\n }\n};\n\n// TODO add some authorize helper components for alert source and individual alert rules\n\n// check if some action is allowed from the abilities\nfunction actionsAllowed(abilities: Abilities, actions: T[]) {\n return chain(abilities)\n .pick(actions)\n .values()\n .value()\n .some(([_supported, allowed]) => allowed === true);\n}\n\nfunction isAlertmanagerAction(action: AlertmanagerAction) {\n return Object.values(AlertmanagerAction).includes(action);\n}\n\nfunction isAlertingAction(action: AlertingAction) {\n return Object.values(AlertingAction).includes(action);\n}\n","import { css } from '@emotion/css';\nimport React from 'react';\n\nimport { GrafanaTheme2 } from '@grafana/data/src';\nimport { Alert, useStyles2 } from '@grafana/ui/src';\n\nimport { AlertmanagerChoice } from '../../../../plugins/datasource/alertmanager/types';\nimport { alertmanagerApi } from '../api/alertmanagerApi';\nimport { GRAFANA_RULES_SOURCE_NAME } from '../utils/datasource';\n\ninterface GrafanaAlertmanagerDeliveryWarningProps {\n currentAlertmanager: string;\n}\n\nexport function GrafanaAlertmanagerDeliveryWarning({ currentAlertmanager }: GrafanaAlertmanagerDeliveryWarningProps) {\n const styles = useStyles2(getStyles);\n const viewingInternalAM = currentAlertmanager === GRAFANA_RULES_SOURCE_NAME;\n\n const { currentData: amChoiceStatus } = alertmanagerApi.endpoints.getAlertmanagerChoiceStatus.useQuery(undefined, {\n skip: !viewingInternalAM,\n });\n\n const interactsWithExternalAMs =\n amChoiceStatus?.alertmanagersChoice &&\n [AlertmanagerChoice.External, AlertmanagerChoice.All].includes(amChoiceStatus?.alertmanagersChoice);\n\n if (!interactsWithExternalAMs || !viewingInternalAM) {\n return null;\n }\n\n const hasActiveExternalAMs = amChoiceStatus.numExternalAlertmanagers > 0;\n\n if (amChoiceStatus.alertmanagersChoice === AlertmanagerChoice.External) {\n return (\n \n Grafana is configured to send alerts to external Alertmanagers only. Changing Grafana Alertmanager configuration\n will not affect delivery of your alerts.\n \n To change your Alertmanager setup, go to the Alerting Admin page. If you do not have access, contact your\n Administrator.\n
\n \n );\n }\n\n if (amChoiceStatus.alertmanagersChoice === AlertmanagerChoice.All && hasActiveExternalAMs) {\n return (\n \n Ensure you make configuration changes in the correct Alertmanagers; both internal and external. Changing one\n will not affect the others.\n \n To change your Alertmanager setup, go to the Alerting Admin page. If you do not have access, contact your\n Administrator.\n
\n \n );\n }\n\n return null;\n}\n\nconst getStyles = (theme: GrafanaTheme2) => ({\n adminHint: css`\n font-size: ${theme.typography.bodySmall.fontSize};\n font-weight: ${theme.typography.bodySmall.fontWeight};\n `,\n});\n","import React from 'react';\n\nimport { IconName, Tooltip, LinkButton, Button } from '@grafana/ui';\nimport { PopoverContent, TooltipPlacement } from '@grafana/ui/src/components/Tooltip';\n\ninterface Props {\n tooltip: PopoverContent;\n icon: IconName;\n className?: string;\n tooltipPlacement?: TooltipPlacement;\n to?: string;\n target?: string;\n onClick?: () => void;\n 'data-testid'?: string;\n}\n\nexport const ActionIcon = ({\n tooltip,\n icon,\n to,\n target,\n onClick,\n className,\n tooltipPlacement = 'top',\n ...rest\n}: Props) => {\n const ariaLabel = typeof tooltip === 'string' ? tooltip : undefined;\n\n return (\n \n {to ? (\n \n ) : (\n \n )}\n \n );\n};\n","import React from 'react';\n\nimport { AlertState } from 'app/plugins/datasource/alertmanager/types';\n\nimport { State, StateTag } from '../StateTag';\n\nconst alertStateToState: Record = {\n [AlertState.Active]: 'bad',\n [AlertState.Unprocessed]: 'neutral',\n [AlertState.Suppressed]: 'info',\n};\n\ninterface Props {\n state: AlertState;\n}\n\nexport const AmAlertStateTag = ({ state }: Props) => {state} ;\n","import { css } from '@emotion/css';\n\nimport { GrafanaTheme2 } from '@grafana/data';\n\nexport const getAlertTableStyles = (theme: GrafanaTheme2) => ({\n table: css`\n width: 100%;\n border-radius: ${theme.shape.radius.default};\n border: solid 1px ${theme.colors.border.weak};\n background-color: ${theme.colors.background.secondary};\n\n th {\n padding: ${theme.spacing(1)};\n }\n\n td {\n padding: 0 ${theme.spacing(1)};\n }\n\n tr {\n height: 38px;\n }\n `,\n evenRow: css`\n background-color: ${theme.colors.background.primary};\n `,\n colExpand: css`\n width: 36px;\n `,\n nameCell: css`\n gap: ${theme.spacing(1)};\n `,\n actionsCell: css`\n text-align: right;\n width: 1%;\n white-space: nowrap;\n\n & > * + * {\n margin-left: ${theme.spacing(0.5)};\n }\n `,\n});\n"],"names":["useCleanup","cleanupAction","dispatch","selectorRef","MatchersField","className","styles","getStyles","formApi","control","register","errors","matchers","append","remove","Field","matcher","index","Input","InputControl","onChange","ref","field","Select","value","IconButton","Button","newMatcher","theme","SilencePeriod","getValues","onChangeStartsAt","startsAt","startsAtInvalid","onChangeEndsAt","endsAt","endsAtInvalid","onChangeTimeZone","timeZone","invalid","from","to","TimeRangeInput","newValue","SilencedInstancesPreview","amSourceName","useGetAlertmanagerAlertsQuery","alertmanagerApi","columns","useColumns","hasValidMatchers","alerts","isFetching","isError","tableItemAlerts","alert","Badge","Alert","LoadingPlaceholder","DynamicTable","data","AmAlertStateTag","AlertLabels","defaultsFromQuery","searchParams","defaults","comment","formMatchers","getDefaultFormValues","silence","now","interval","config","SilencesEditor","alertManagerSourceName","urlSearchParams","useURLSearchParams","defaultValues","formAPI","matchersForPreview","setMatchersForPreview","loading","useUnifiedAlertingSelector","state","handleSubmit","formState","watch","setValue","clearErrors","onSubmit","id","createdBy","matchersFields","payload","duration","matcherFields","prevDuration","setPrevDuration","useDebounce","startValue","nextDuration","newMatchers","m","userLogged","FieldSet","TextArea","ActionButton","restProps","getStyle","Matchers","TagList","NoSilencesSplash","permissions","EmptyListCTA","CallToActionCard","SilencedAlertsTableRow","isCollapsed","setIsCollapsed","alertName","name","labelKey","labelValue","CollapseToggle","collapsed","SilencedAlertsTable","silencedAlerts","tableStyles","SilenceDetails","dateDisplayFormat","startsAtDate","endsAtDate","silenceStateToState","SilenceStateTag","StateTag","getQueryStringKey","SilencesFilter","queryStringKey","setQueryStringKey","queryParams","setQueryParams","useQueryParams","queryString","handleQueryStringChange","e","target","clearFilters","inputInvalid","Label","Stack","Tooltip","Icon","SilencesTable","silences","alertManagerAlerts","filteredSilencesNotExpired","useFilteredSilences","filteredSilencesExpired","silenceStateInParams","showExpiredFromUrl","itemsNotExpired","findSilencedAlerts","itemsExpired","Authorize","SilenceList","CollapsableSection","items","dataTestId","expired","silenceIdsString","isEqual","isRegex","updateSupported","updateAllowed","handleExpireSilenceClick","status","Link","ActionIcon","defaultPageNav","useSilenceNavData","isExact","path","pageNav","setPageNav","Silences","selectedAlertmanager","alertsRequests","alertsRequest","amFeatures","featureDiscoveryApi","fetchAll","result","error","getSilenceById","mimirLazyInitError","GrafanaAlertmanagerDeliveryWarning","match","SilencesPage","actions","children","alertmanagerActions","isAlertmanagerAction","alertSourceActions","isAlertingAction","AuthorizeAlertmanager","AuthorizeAlertsource","alertmanagerAbilties","actionsAllowed","alertSourceAbilities","abilities","_supported","allowed","action","currentAlertmanager","viewingInternalAM","amChoiceStatus","hasActiveExternalAMs","tooltip","icon","onClick","tooltipPlacement","rest","ariaLabel","alertStateToState","getAlertTableStyles"],"sourceRoot":""}