View File Name : 0.c88fc16b6533c8976681.js.map
\n }\n onClose={onClose}\n >\n {activeTab === 'yaml' &&
}\n \n );\n};\n\ninterface RuleInspectorTabsProps
{\n tabs: Array<{ label: string; value: T }>;\n activeTab: T;\n setActiveTab: (tab: T) => void;\n}\n\nexport function RuleInspectorTabs({ tabs, activeTab, setActiveTab }: RuleInspectorTabsProps) {\n return (\n \n {tabs.map((tab, index) => {\n return (\n setActiveTab(tab.value)}\n active={activeTab === tab.value}\n />\n );\n })}\n \n );\n}\n\ninterface YamlTabProps {\n onSubmit: (newModel: RuleFormValues) => void;\n}\n\nconst InspectorYamlTab = ({ onSubmit }: YamlTabProps) => {\n const styles = useStyles2(yamlTabStyle);\n const { getValues } = useFormContext();\n\n const yamlValues = formValuesToRulerRuleDTO(getValues());\n const [alertRuleAsYaml, setAlertRuleAsYaml] = useState(dump(yamlValues));\n\n const onApply = () => {\n const rulerRule = load(alertRuleAsYaml) as RulerRuleDTO;\n const currentFormValues = getValues();\n\n const yamlFormValues = rulerRuleToRuleFormValues(rulerRule);\n onSubmit({ ...currentFormValues, ...yamlFormValues });\n };\n\n return (\n <>\n \n \n Apply\n \n } theme=\"info\" placement=\"left-start\" interactive={true}>\n \n \n
\n\n \n
\n {({ height }) => (\n \n )}\n \n
\n >\n );\n};\n\nfunction YamlContentInfo() {\n return (\n \n The YAML content in the editor only contains alert rule configuration
\n To configure Prometheus, you need to provide the rest of the{' '}\n
\n configuration file content.\n \n
\n );\n}\n\nfunction rulerRuleToRuleFormValues(rulerRule: RulerRuleDTO): Partial {\n if (isAlertingRulerRule(rulerRule)) {\n return alertingRulerRuleToRuleForm(rulerRule);\n } else if (isRecordingRulerRule(rulerRule)) {\n return recordingRulerRuleToRuleForm(rulerRule);\n }\n\n return {};\n}\n\nexport const yamlTabStyle = (theme: GrafanaTheme2) => ({\n content: css`\n flex-grow: 1;\n height: 100%;\n padding-bottom: 16px;\n margin-bottom: ${theme.spacing(2)};\n `,\n applyButton: css`\n display: flex;\n flex-direction: row;\n justify-content: space-between;\n align-items: center;\n flex-grow: 0;\n margin-bottom: ${theme.spacing(2)};\n `,\n});\n\nexport const drawerStyles = () => ({\n subtitle: css`\n display: flex;\n align-items: center;\n justify-content: space-between;\n `,\n});\n","import { IconName } from '@grafana/ui';\n\nexport const INTEGRATION_ICONS: Record = {\n discord: 'discord',\n email: 'envelope',\n googlechat: 'google-hangouts-alt',\n hipchat: 'hipchat',\n line: 'line',\n pagerduty: 'pagerduty',\n slack: 'slack',\n teams: 'microsoft',\n telegram: 'telegram-alt',\n webhook: 'link',\n sns: 'amazon',\n};\n","import { isArray, pick, reduce } from 'lodash';\n\nimport {\n AlertmanagerGroup,\n MatcherOperator,\n ObjectMatcher,\n Route,\n RouteWithID,\n} from 'app/plugins/datasource/alertmanager/types';\nimport { Labels } from 'app/types/unified-alerting-dto';\n\nimport { Label, normalizeMatchers, unquoteWithUnescape } from './matchers';\n\n// If a policy has no matchers it still can be a match, hence matchers can be empty and match can be true\n// So we cannot use null as an indicator of no match\ninterface LabelMatchResult {\n match: boolean;\n matcher: ObjectMatcher | null;\n}\n\nexport const INHERITABLE_KEYS = ['receiver', 'group_by', 'group_wait', 'group_interval', 'repeat_interval'] as const;\nexport type InheritableKeys = typeof INHERITABLE_KEYS;\nexport type InheritableProperties = Pick;\n\ntype LabelsMatch = Map;\n\ninterface MatchingResult {\n matches: boolean;\n labelsMatch: LabelsMatch;\n}\n\n// returns a match results for given set of matchers (from a policy for instance) and a set of labels\nexport function matchLabels(matchers: ObjectMatcher[], labels: Label[]): MatchingResult {\n const matches = matchLabelsSet(matchers, labels);\n\n // create initial map of label => match result\n const labelsMatch: LabelsMatch = new Map(labels.map((label) => [label, { match: false, matcher: null }]));\n\n // for each matcher, check which label it matched for\n matchers.forEach((matcher) => {\n const matchingLabel = labels.find((label) => isLabelMatch(matcher, label));\n\n // record that matcher for the label\n if (matchingLabel) {\n labelsMatch.set(matchingLabel, {\n match: true,\n matcher,\n });\n }\n });\n\n return { matches, labelsMatch };\n}\n\n// Compare set of matchers to set of label\nexport function matchLabelsSet(matchers: ObjectMatcher[], labels: Label[]): boolean {\n for (const matcher of matchers) {\n if (!isLabelMatchInSet(matcher, labels)) {\n return false;\n }\n }\n return true;\n}\n\nexport interface AlertInstanceMatch {\n instance: Labels;\n labelsMatch: LabelsMatch;\n}\n\nexport interface RouteMatchResult {\n route: T;\n labelsMatch: LabelsMatch;\n}\n\n// Match does a depth-first left-to-right search through the route tree\n// and returns the matching routing nodes.\n\n// If the current node is not a match, return nothing\n// Normalization should have happened earlier in the code\nfunction findMatchingRoutes(route: T, labels: Label[]): Array> {\n let childMatches: Array> = [];\n\n // If the current node is not a match, return nothing\n const matchResult = matchLabels(route.object_matchers ?? [], labels);\n if (!matchResult.matches) {\n return [];\n }\n\n // If the current node matches, recurse through child nodes\n if (route.routes) {\n for (const child of route.routes) {\n let matchingChildren = findMatchingRoutes(child, labels);\n // TODO how do I solve this typescript thingy? It looks correct to me /shrug\n // @ts-ignore\n childMatches = childMatches.concat(matchingChildren);\n // we have matching children and we don't want to continue, so break here\n if (matchingChildren.length && !child.continue) {\n break;\n }\n }\n }\n\n // If no child nodes were matches, the current node itself is a match.\n if (childMatches.length === 0) {\n childMatches.push({ route, labelsMatch: matchResult.labelsMatch });\n }\n\n return childMatches;\n}\n\n// This is a performance improvement to normalize matchers only once and use the normalized version later on\nexport function normalizeRoute(rootRoute: RouteWithID): RouteWithID {\n function normalizeRoute(route: RouteWithID) {\n route.object_matchers = normalizeMatchers(route);\n delete route.matchers;\n delete route.match;\n delete route.match_re;\n route.routes?.forEach(normalizeRoute);\n }\n\n const normalizedRootRoute = structuredClone(rootRoute);\n normalizeRoute(normalizedRootRoute);\n\n return normalizedRootRoute;\n}\n\nexport function unquoteRouteMatchers(route: RouteWithID): RouteWithID {\n function unquoteRoute(route: RouteWithID) {\n route.object_matchers = route.object_matchers?.map(([name, operator, value]) => {\n return [name, operator, unquoteWithUnescape(value)];\n });\n route.routes?.forEach(unquoteRoute);\n }\n\n const unwrappedRootRoute = structuredClone(route);\n unquoteRoute(unwrappedRootRoute);\n\n return unwrappedRootRoute;\n}\n\n/**\n * find all of the groups that have instances that match the route, thay way we can find all instances\n * (and their grouping) for the given route\n */\nfunction findMatchingAlertGroups(\n routeTree: Route,\n route: Route,\n alertGroups: AlertmanagerGroup[]\n): AlertmanagerGroup[] {\n const matchingGroups: AlertmanagerGroup[] = [];\n\n return alertGroups.reduce((acc, group) => {\n // find matching alerts in the current group\n const matchingAlerts = group.alerts.filter((alert) => {\n const labels = Object.entries(alert.labels);\n return findMatchingRoutes(routeTree, labels).some((matchingRoute) => matchingRoute.route === route);\n });\n\n // if the groups has any alerts left after matching, add it to the results\n if (matchingAlerts.length) {\n acc.push({\n ...group,\n alerts: matchingAlerts,\n });\n }\n\n return acc;\n }, matchingGroups);\n}\n\n// inherited properties are config properties that exist on the parent route (or its inherited properties) but not on the child route\nfunction getInheritedProperties(\n parentRoute: Route,\n childRoute: Route,\n propertiesParentInherited?: InheritableProperties\n): InheritableProperties {\n const propsFromParent: InheritableProperties = pick(parentRoute, INHERITABLE_KEYS);\n const inheritableProperties: InheritableProperties = {\n ...propsFromParent,\n ...propertiesParentInherited,\n };\n\n const inherited = reduce(\n inheritableProperties,\n (inheritedProperties: InheritableProperties, parentValue, property) => {\n const parentHasValue = parentValue != null;\n\n const inheritableValues = [undefined, '', null];\n // @ts-ignore\n const childIsInheriting = inheritableValues.some((value) => childRoute[property] === value);\n const inheritFromValue = childIsInheriting && parentHasValue;\n\n const inheritEmptyGroupByFromParent =\n property === 'group_by' &&\n parentHasValue &&\n isArray(childRoute[property]) &&\n childRoute[property]?.length === 0;\n\n const inheritFromParent = inheritFromValue || inheritEmptyGroupByFromParent;\n\n if (inheritFromParent) {\n // @ts-ignore\n inheritedProperties[property] = parentValue;\n }\n\n return inheritedProperties;\n },\n {}\n );\n\n return inherited;\n}\n\n/**\n * This function will compute the full tree with inherited properties – this is mostly used for search and filtering\n */\nexport function computeInheritedTree(parent: T): T {\n return {\n ...parent,\n routes: parent.routes?.map((child) => {\n const inheritedProperties = getInheritedProperties(parent, child);\n\n return computeInheritedTree({\n ...child,\n ...inheritedProperties,\n });\n }),\n };\n}\n\ntype OperatorPredicate = (labelValue: string, matcherValue: string) => boolean;\nconst OperatorFunctions: Record = {\n [MatcherOperator.equal]: (lv, mv) => lv === mv,\n [MatcherOperator.notEqual]: (lv, mv) => lv !== mv,\n [MatcherOperator.regex]: (lv, mv) => new RegExp(mv).test(lv),\n [MatcherOperator.notRegex]: (lv, mv) => !new RegExp(mv).test(lv),\n};\n\nfunction isLabelMatchInSet(matcher: ObjectMatcher, labels: Label[]): boolean {\n const [matcherKey, operator, matcherValue] = matcher;\n\n let labelValue = ''; // matchers that have no labels are treated as empty string label values\n const labelForMatcher = Object.fromEntries(labels)[matcherKey];\n if (labelForMatcher) {\n labelValue = labelForMatcher;\n }\n\n const matchFunction = OperatorFunctions[operator];\n if (!matchFunction) {\n throw new Error(`no such operator: ${operator}`);\n }\n\n return matchFunction(labelValue, matcherValue);\n}\n\n// ⚠️ DO NOT USE THIS FUNCTION FOR ROUTE SELECTION ALGORITHM\n// for route selection algorithm, always compare a single matcher to the entire label set\n// see \"matchLabelsSet\"\nfunction isLabelMatch(matcher: ObjectMatcher, label: Label): boolean {\n let [labelKey, labelValue] = label;\n const [matcherKey, operator, matcherValue] = matcher;\n\n if (labelKey !== matcherKey) {\n return false;\n }\n\n const matchFunction = OperatorFunctions[operator];\n if (!matchFunction) {\n throw new Error(`no such operator: ${operator}`);\n }\n\n return matchFunction(labelValue, matcherValue);\n}\n\nexport { findMatchingAlertGroups, findMatchingRoutes, getInheritedProperties, isLabelMatchInSet };\n"],"names":["ConditionalWrap","children","shouldWrap","wrap","_ref","ONCALL_INTEGRATION_V2_FEATURE","getProxyApiUrl","path","onCallApi","build","response","isPaginatedResponse","name","integration","useGrafanaOnCallIntegrationsQuery","isOnCallFetchError","error","Authorize","actions","alertmanagerActions","isAlertmanagerAction","alertSourceActions","isAlertingAction","AuthorizeAlertmanager","AuthorizeAlertsource","alertmanagerAbilties","actionsAllowed","alertSourceAbilities","abilities","_supported","allowed","action","GrafanaAlertmanagerDeliveryWarning","currentAlertmanager","styles","getStyles","viewingInternalAM","amChoiceStatus","hasActiveExternalAMs","theme","Strong","FileExportPreview","format","textDefinition","downloadFileName","onClose","fileExportPreviewStyles","provider","onDownload","blob","formattedTextDefinition","FileExportInlineDocumentation","height","exportProvider","type","exportInlineDoc","title","component","GrafanaExportDrawer","activeTab","onTabChange","formatProviders","grafanaRulesTabs","JsonExportProvider","raw","YamlExportProvider","HclExportProvider","allGrafanaExportProviders","jsonAndYamlGrafanaExportProviders","GRAFANA_ONCALL_INTEGRATION_TYPE","ReceiverTypes","isInOnCallIntegrations","url","integrationsUrls","isOnCallReceiver","receiver","integrations","onlyOneIntegration","isOnCall","i","cloudRulesTabs","RuleInspector","setActiveTab","setValue","drawerStyles","onApply","formValues","key","RuleInspectorTabs","InspectorYamlTab","tabs","tab","index","onSubmit","yamlTabStyle","getValues","yamlValues","alertRuleAsYaml","setAlertRuleAsYaml","rulerRule","currentFormValues","yamlFormValues","rulerRuleToRuleFormValues","YamlContentInfo","INTEGRATION_ICONS","INHERITABLE_KEYS","matchLabels","matchers","labels","matches","matchLabelsSet","labelsMatch","label","matcher","matchingLabel","isLabelMatch","isLabelMatchInSet","findMatchingRoutes","route","childMatches","matchResult","child","matchingChildren","normalizeRoute","rootRoute","normalizedRootRoute","unquoteRouteMatchers","unquoteRoute","operator","value","unwrappedRootRoute","findMatchingAlertGroups","routeTree","alertGroups","matchingGroups","acc","group","matchingAlerts","alert","matchingRoute","getInheritedProperties","parentRoute","childRoute","propertiesParentInherited","inheritableProperties","inheritedProperties","parentValue","property","parentHasValue","inheritFromValue","inheritEmptyGroupByFromParent","computeInheritedTree","parent","OperatorFunctions","lv","mv","matcherKey","matcherValue","labelValue","labelForMatcher","matchFunction","labelKey"],"sourceRoot":""}