{"version":3,"file":"FolderAlerting.cf636db5eef730ed8461.js","mappings":"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","sources":["webpack://grafana/./public/app/features/alerting/unified/hooks/useCombinedRuleNamespaces.ts","webpack://grafana/./public/app/features/alerting/unified/hooks/useURLSearchParams.ts","webpack://grafana/./public/app/features/alerting/unified/AlertsFolderView.tsx","webpack://grafana/./public/app/features/alerting/unified/hooks/usePagination.ts","webpack://grafana/./public/app/features/folders/FolderAlerting.tsx"],"sourcesContent":["import { useMemo, useRef } from 'react';\n\nimport {\n CombinedRule,\n CombinedRuleGroup,\n CombinedRuleNamespace,\n Rule,\n RuleGroup,\n RuleNamespace,\n RulesSource,\n} from 'app/types/unified-alerting';\nimport { RulerRuleDTO, RulerRuleGroupDTO, RulerRulesConfigDTO } from 'app/types/unified-alerting-dto';\n\nimport {\n getAllRulesSources,\n getRulesSourceByName,\n isCloudRulesSource,\n isGrafanaRulesSource,\n} from '../utils/datasource';\nimport { isAlertingRule, isAlertingRulerRule, isRecordingRulerRule } from '../utils/rules';\n\nimport { useUnifiedAlertingSelector } from './useUnifiedAlertingSelector';\n\ninterface CacheValue {\n promRules?: RuleNamespace[];\n rulerRules?: RulerRulesConfigDTO | null;\n result: CombinedRuleNamespace[];\n}\n\n// this little monster combines prometheus rules and ruler rules to produce a unified data structure\n// can limit to a single rules source\nexport function useCombinedRuleNamespaces(rulesSourceName?: string): CombinedRuleNamespace[] {\n const promRulesResponses = useUnifiedAlertingSelector((state) => state.promRules);\n const rulerRulesResponses = useUnifiedAlertingSelector((state) => state.rulerRules);\n\n // cache results per rules source, so we only recalculate those for which results have actually changed\n const cache = useRef>({});\n\n const rulesSources = useMemo((): RulesSource[] => {\n if (rulesSourceName) {\n const rulesSource = getRulesSourceByName(rulesSourceName);\n if (!rulesSource) {\n throw new Error(`Unknown rules source: ${rulesSourceName}`);\n }\n return [rulesSource];\n }\n return getAllRulesSources();\n }, [rulesSourceName]);\n\n return useMemo(\n () =>\n rulesSources\n .map((rulesSource): CombinedRuleNamespace[] => {\n const rulesSourceName = isCloudRulesSource(rulesSource) ? rulesSource.name : rulesSource;\n const promRules = promRulesResponses[rulesSourceName]?.result;\n const rulerRules = rulerRulesResponses[rulesSourceName]?.result;\n\n const cached = cache.current[rulesSourceName];\n if (cached && cached.promRules === promRules && cached.rulerRules === rulerRules) {\n return cached.result;\n }\n const namespaces: Record = {};\n\n // first get all the ruler rules in\n Object.entries(rulerRules || {}).forEach(([namespaceName, groups]) => {\n const namespace: CombinedRuleNamespace = {\n rulesSource,\n name: namespaceName,\n groups: [],\n };\n namespaces[namespaceName] = namespace;\n addRulerGroupsToCombinedNamespace(namespace, groups);\n });\n\n // then correlate with prometheus rules\n promRules?.forEach(({ name: namespaceName, groups }) => {\n const ns = (namespaces[namespaceName] = namespaces[namespaceName] || {\n rulesSource,\n name: namespaceName,\n groups: [],\n });\n\n addPromGroupsToCombinedNamespace(ns, groups);\n });\n\n const result = Object.values(namespaces);\n\n cache.current[rulesSourceName] = { promRules, rulerRules, result };\n return result;\n })\n .flat(),\n [promRulesResponses, rulerRulesResponses, rulesSources]\n );\n}\n\n// merge all groups in case of grafana managed, essentially treating namespaces (folders) as groups\nexport function flattenGrafanaManagedRules(namespaces: CombinedRuleNamespace[]) {\n return namespaces.map((namespace) => {\n const newNamespace: CombinedRuleNamespace = {\n ...namespace,\n groups: [],\n };\n\n // add default group with ungrouped rules\n newNamespace.groups.push({\n name: 'default',\n rules: sortRulesByName(namespace.groups.flatMap((group) => group.rules)),\n });\n\n return newNamespace;\n });\n}\n\nexport function sortRulesByName(rules: CombinedRule[]) {\n return rules.sort((a, b) => a.name.localeCompare(b.name));\n}\n\nfunction addRulerGroupsToCombinedNamespace(namespace: CombinedRuleNamespace, groups: RulerRuleGroupDTO[]): void {\n namespace.groups = groups.map((group) => {\n const combinedGroup: CombinedRuleGroup = {\n name: group.name,\n interval: group.interval,\n source_tenants: group.source_tenants,\n rules: [],\n };\n combinedGroup.rules = group.rules.map((rule) => rulerRuleToCombinedRule(rule, namespace, combinedGroup));\n return combinedGroup;\n });\n}\n\nfunction addPromGroupsToCombinedNamespace(namespace: CombinedRuleNamespace, groups: RuleGroup[]): void {\n groups.forEach((group) => {\n let combinedGroup = namespace.groups.find((g) => g.name === group.name);\n if (!combinedGroup) {\n combinedGroup = {\n name: group.name,\n rules: [],\n };\n namespace.groups.push(combinedGroup);\n }\n\n (group.rules ?? []).forEach((rule) => {\n const existingRule = getExistingRuleInGroup(rule, combinedGroup!, namespace.rulesSource);\n if (existingRule) {\n existingRule.promRule = rule;\n } else {\n combinedGroup!.rules.push(promRuleToCombinedRule(rule, namespace, combinedGroup!));\n }\n });\n });\n}\n\nfunction promRuleToCombinedRule(rule: Rule, namespace: CombinedRuleNamespace, group: CombinedRuleGroup): CombinedRule {\n return {\n name: rule.name,\n query: rule.query,\n labels: rule.labels || {},\n annotations: isAlertingRule(rule) ? rule.annotations || {} : {},\n promRule: rule,\n namespace: namespace,\n group,\n };\n}\n\nfunction rulerRuleToCombinedRule(\n rule: RulerRuleDTO,\n namespace: CombinedRuleNamespace,\n group: CombinedRuleGroup\n): CombinedRule {\n return isAlertingRulerRule(rule)\n ? {\n name: rule.alert,\n query: rule.expr,\n labels: rule.labels || {},\n annotations: rule.annotations || {},\n rulerRule: rule,\n namespace,\n group,\n }\n : isRecordingRulerRule(rule)\n ? {\n name: rule.record,\n query: rule.expr,\n labels: rule.labels || {},\n annotations: {},\n rulerRule: rule,\n namespace,\n group,\n }\n : {\n name: rule.grafana_alert.title,\n query: '',\n labels: rule.labels || {},\n annotations: rule.annotations || {},\n rulerRule: rule,\n namespace,\n group,\n };\n}\n\n// find existing rule in group that matches the given prom rule\nfunction getExistingRuleInGroup(\n rule: Rule,\n group: CombinedRuleGroup,\n rulesSource: RulesSource\n): CombinedRule | undefined {\n if (isGrafanaRulesSource(rulesSource)) {\n // assume grafana groups have only the one rule. check name anyway because paranoid\n return group!.rules.find((existingRule) => existingRule.name === rule.name);\n }\n return (\n // try finding a rule that matches name, labels, annotations and query\n group!.rules.find(\n (existingRule) => !existingRule.promRule && isCombinedRuleEqualToPromRule(existingRule, rule, true)\n ) ??\n // if that fails, try finding a rule that only matches name, labels and annotations.\n // loki & prom can sometimes modify the query so it doesnt match, eg `2 > 1` becomes `1`\n group!.rules.find(\n (existingRule) => !existingRule.promRule && isCombinedRuleEqualToPromRule(existingRule, rule, false)\n )\n );\n}\n\nfunction isCombinedRuleEqualToPromRule(combinedRule: CombinedRule, rule: Rule, checkQuery = true): boolean {\n if (combinedRule.name === rule.name) {\n return (\n JSON.stringify([\n checkQuery ? hashQuery(combinedRule.query) : '',\n combinedRule.labels,\n combinedRule.annotations,\n ]) ===\n JSON.stringify([\n checkQuery ? hashQuery(rule.query) : '',\n rule.labels || {},\n isAlertingRule(rule) ? rule.annotations || {} : {},\n ])\n );\n }\n return false;\n}\n\n// there can be slight differences in how prom & ruler render a query, this will hash them accounting for the differences\nfunction hashQuery(query: string) {\n // one of them might be wrapped in parens\n if (query.length > 1 && query[0] === '(' && query[query.length - 1] === ')') {\n query = query.slice(1, -1);\n }\n // whitespace could be added or removed\n query = query.replace(/\\s|\\n/g, '');\n // labels matchers can be reordered, so sort the enitre string, esentially comparing just the character counts\n return query.split('').sort().join('');\n}\n","import { useCallback, useMemo } from 'react';\nimport { useLocation } from 'react-router-dom';\n\nimport { locationService } from '@grafana/runtime';\n\nexport function useURLSearchParams(): [\n URLSearchParams,\n (searchValues: Record, replace?: boolean) => void\n] {\n const { search } = useLocation();\n const queryParams = useMemo(() => new URLSearchParams(search), [search]);\n\n const update = useCallback((searchValues: Record, replace?: boolean) => {\n locationService.partial(searchValues, replace);\n }, []);\n\n return [queryParams, update];\n}\n","import { css } from '@emotion/css';\nimport { isEqual, orderBy, uniqWith } from 'lodash';\nimport React, { useEffect, useState } from 'react';\nimport { useDispatch } from 'react-redux';\nimport { useDebounce } from 'react-use';\n\nimport { GrafanaTheme2, SelectableValue } from '@grafana/data';\nimport { Stack } from '@grafana/experimental';\nimport { Card, FilterInput, Icon, Pagination, Select, TagList, useStyles2 } from '@grafana/ui';\nimport { DEFAULT_PER_PAGE_PAGINATION } from 'app/core/constants';\nimport { getQueryParamValue } from 'app/core/utils/query';\nimport { FolderState } from 'app/types';\nimport { CombinedRule } from 'app/types/unified-alerting';\n\nimport { useCombinedRuleNamespaces } from './hooks/useCombinedRuleNamespaces';\nimport { usePagination } from './hooks/usePagination';\nimport { useURLSearchParams } from './hooks/useURLSearchParams';\nimport { fetchPromRulesAction, fetchRulerRulesAction } from './state/actions';\nimport { labelsMatchMatchers, matchersToString, parseMatcher, parseMatchers } from './utils/alertmanager';\nimport { GRAFANA_RULES_SOURCE_NAME } from './utils/datasource';\nimport { createViewLink } from './utils/misc';\n\ninterface Props {\n folder: FolderState;\n}\n\nenum SortOrder {\n Ascending = 'alpha-asc',\n Descending = 'alpha-desc',\n}\n\nconst sortOptions: Array> = [\n { label: 'Alphabetically [A-Z]', value: SortOrder.Ascending },\n { label: 'Alphabetically [Z-A]', value: SortOrder.Descending },\n];\n\nexport const AlertsFolderView = ({ folder }: Props) => {\n const styles = useStyles2(getStyles);\n const dispatch = useDispatch();\n\n const onTagClick = (tagName: string) => {\n const matchers = parseMatchers(labelFilter);\n const tagMatcherField = parseMatcher(tagName);\n const uniqueMatchers = uniqWith([...matchers, tagMatcherField], isEqual);\n const matchersString = matchersToString(uniqueMatchers);\n setLabelFilter(matchersString);\n };\n\n useEffect(() => {\n dispatch(fetchPromRulesAction({ rulesSourceName: GRAFANA_RULES_SOURCE_NAME }));\n dispatch(fetchRulerRulesAction({ rulesSourceName: GRAFANA_RULES_SOURCE_NAME }));\n }, [dispatch]);\n\n const combinedNamespaces = useCombinedRuleNamespaces(GRAFANA_RULES_SOURCE_NAME);\n const { nameFilter, labelFilter, sortOrder, setNameFilter, setLabelFilter, setSortOrder } =\n useAlertsFolderViewParams();\n\n const matchingNamespace = combinedNamespaces.find((namespace) => namespace.name === folder.title);\n const alertRules = matchingNamespace?.groups.flatMap((group) => group.rules) ?? [];\n\n const filteredRules = filterAndSortRules(alertRules, nameFilter, labelFilter, sortOrder ?? SortOrder.Ascending);\n\n const hasNoResults = alertRules.length === 0 || filteredRules.length === 0;\n const { page, numberOfPages, onPageChange, pageItems } = usePagination(filteredRules, 1, DEFAULT_PER_PAGE_PAGINATION);\n\n return (\n
\n \n \n \n \n value={sortOrder}\n onChange={({ value }) => value && setSortOrder(value)}\n options={sortOptions}\n width={25}\n aria-label=\"Sort\"\n placeholder={`Sort (Default A-Z)`}\n prefix={}\n />\n \n \n\n \n {pageItems.map((currentRule) => (\n \n {currentRule.name}\n \n `${label}=${value}`)}\n />\n \n \n
\n {folder.title}\n
\n
\n \n ))}\n
\n {hasNoResults &&
No alert rules found
}\n
\n \n
\n
\n
\n );\n};\n\nenum AlertFolderViewParams {\n nameFilter = 'nameFilter',\n labelFilter = 'labelFilter',\n sortOrder = 'sort',\n}\n\nfunction useAlertsFolderViewParams() {\n const [searchParams, setSearchParams] = useURLSearchParams();\n\n const [nameFilter, setNameFilter] = useState(searchParams.get(AlertFolderViewParams.nameFilter) ?? '');\n const [labelFilter, setLabelFilter] = useState(searchParams.get(AlertFolderViewParams.labelFilter) ?? '');\n\n const sortParam = searchParams.get(AlertFolderViewParams.sortOrder);\n const [sortOrder, setSortOrder] = useState(\n sortParam === SortOrder.Ascending\n ? SortOrder.Ascending\n : sortParam === SortOrder.Descending\n ? SortOrder.Descending\n : undefined\n );\n\n useDebounce(\n () =>\n setSearchParams(\n {\n [AlertFolderViewParams.nameFilter]: getQueryParamValue(nameFilter),\n [AlertFolderViewParams.labelFilter]: getQueryParamValue(labelFilter),\n [AlertFolderViewParams.sortOrder]: getQueryParamValue(sortOrder),\n },\n true\n ),\n 400,\n [nameFilter, labelFilter, sortOrder]\n );\n\n return { nameFilter, labelFilter, sortOrder, setNameFilter, setLabelFilter, setSortOrder };\n}\n\nfunction filterAndSortRules(\n originalRules: CombinedRule[],\n nameFilter: string,\n labelFilter: string,\n sortOrder: SortOrder\n) {\n const matchers = parseMatchers(labelFilter);\n let rules = originalRules.filter(\n (rule) => rule.name.toLowerCase().includes(nameFilter.toLowerCase()) && labelsMatchMatchers(rule.labels, matchers)\n );\n\n return orderBy(rules, (x) => x.name.toLowerCase(), [sortOrder === SortOrder.Ascending ? 'asc' : 'desc']);\n}\n\nexport const getStyles = (theme: GrafanaTheme2) => ({\n container: css`\n padding: ${theme.spacing(1)};\n `,\n card: css`\n grid-template-columns: auto 1fr 2fr;\n margin: 0;\n `,\n pagination: css`\n align-self: center;\n `,\n filterLabelsInput: css`\n flex: 1;\n width: auto;\n min-width: 240px;\n `,\n noResults: css`\n padding: ${theme.spacing(2)};\n background-color: ${theme.colors.background.secondary};\n font-style: italic;\n `,\n});\n","import { useEffect, useState } from 'react';\n\nexport function usePagination(items: T[], initialPage: number, itemsPerPage: number) {\n const [page, setPage] = useState(initialPage);\n\n const numberOfPages = Math.ceil(items.length / itemsPerPage);\n\n const firstItemOnPageIndex = itemsPerPage * (page - 1);\n const pageItems = items.slice(firstItemOnPageIndex, firstItemOnPageIndex + itemsPerPage);\n\n const onPageChange = (newPage: number) => {\n setPage(newPage);\n };\n\n // Reset the current page when number of changes has been changed\n useEffect(() => setPage(1), [numberOfPages]);\n\n return { page, onPageChange, numberOfPages, pageItems };\n}\n","import React from 'react';\nimport { useDispatch, useSelector } from 'react-redux';\nimport { useAsync } from 'react-use';\n\nimport Page from 'app/core/components/Page/Page';\nimport { GrafanaRouteComponentProps } from 'app/core/navigation/types';\nimport { getNavModel } from 'app/core/selectors/navModel';\nimport { StoreState } from 'app/types';\n\nimport { AlertsFolderView } from '../alerting/unified/AlertsFolderView';\n\nimport { getFolderByUid } from './state/actions';\nimport { getLoadingNav } from './state/navModel';\n\nexport interface OwnProps extends GrafanaRouteComponentProps<{ uid: string }> {}\n\nconst FolderAlerting = ({ match }: OwnProps) => {\n const dispatch = useDispatch();\n const navIndex = useSelector((state: StoreState) => state.navIndex);\n const folder = useSelector((state: StoreState) => state.folder);\n\n const uid = match.params.uid;\n const navModel = getNavModel(navIndex, `folder-alerting-${uid}`, getLoadingNav(1));\n\n const { loading } = useAsync(async () => dispatch(getFolderByUid(uid)), [getFolderByUid, uid]);\n\n return (\n \n \n \n \n \n );\n};\n\nexport default FolderAlerting;\n"],"names":["useCombinedRuleNamespaces","rulesSourceName","promRulesResponses","useUnifiedAlertingSelector","state","promRules","rulerRulesResponses","rulerRules","cache","useRef","rulesSources","useMemo","rulesSource","getRulesSourceByName","Error","getAllRulesSources","map","isCloudRulesSource","name","result","cached","current","namespaces","Object","entries","forEach","namespaceName","groups","namespace","group","combinedGroup","interval","source_tenants","rules","rule","isAlertingRulerRule","alert","query","expr","labels","annotations","rulerRule","isRecordingRulerRule","record","grafana_alert","title","rulerRuleToCombinedRule","addRulerGroupsToCombinedNamespace","find","g","push","existingRule","isGrafanaRulesSource","promRule","isCombinedRuleEqualToPromRule","getExistingRuleInGroup","isAlertingRule","promRuleToCombinedRule","addPromGroupsToCombinedNamespace","values","flat","flattenGrafanaManagedRules","newNamespace","flatMap","sort","a","b","localeCompare","combinedRule","checkQuery","JSON","stringify","hashQuery","length","slice","replace","split","join","useURLSearchParams","search","useLocation","URLSearchParams","useCallback","searchValues","locationService","SortOrder","sortOptions","label","value","Ascending","Descending","AlertsFolderView","folder","styles","useStyles2","getStyles","dispatch","useDispatch","onTagClick","tagName","matchers","parseMatchers","labelFilter","tagMatcherField","parseMatcher","uniqueMatchers","uniqWith","isEqual","matchersString","matchersToString","setLabelFilter","useEffect","fetchPromRulesAction","GRAFANA_RULES_SOURCE_NAME","fetchRulerRulesAction","combinedNamespaces","nameFilter","sortOrder","setNameFilter","setSortOrder","searchParams","setSearchParams","useState","get","AlertFolderViewParams","sortParam","undefined","useDebounce","getQueryParamValue","useAlertsFolderViewParams","matchingNamespace","alertRules","filteredRules","originalRules","filter","toLowerCase","includes","labelsMatchMatchers","orderBy","x","filterAndSortRules","hasNoResults","page","numberOfPages","onPageChange","pageItems","items","initialPage","itemsPerPage","setPage","Math","ceil","firstItemOnPageIndex","newPage","usePagination","DEFAULT_PER_PAGE_PAGINATION","className","container","Stack","direction","gap","FilterInput","onChange","placeholder","Select","options","width","prefix","Icon","filterLabelsInput","currentRule","Card","href","createViewLink","card","TagList","onClick","tags","noResults","pagination","Pagination","currentPage","onNavigate","hideWhenSinglePage","theme","css","spacing","colors","background","secondary","match","navIndex","useSelector","uid","params","navModel","getNavModel","getLoadingNav","loading","useAsync","async","getFolderByUid","Page","isLoading"],"sourceRoot":""}