{"version":3,"file":"RoutingTreeSelector.mjs","sources":["../../../../../../src/grafana/notificationPolicies/components/RoutingTreeSelector/RoutingTreeSelector.tsx"],"sourcesContent":["import { type ComponentProps, useMemo } from 'react';\n\nimport { type RoutingTree } from '@grafana/api-clients/rtkq/notifications.alerting/v0alpha1';\nimport { t } from '@grafana/i18n';\nimport { Alert, Combobox, type ComboboxOption, MultiCombobox } from '@grafana/ui';\n\nimport { type CustomComboBoxProps } from '../../../common/ComboBox.types';\nimport { USER_DEFINED_TREE_NAME } from '../../consts';\nimport { useListRoutingTrees } from '../../hooks/useRoutingTrees';\n\nconst collator = new Intl.Collator('en', { sensitivity: 'accent' });\n\ntype SingleSelectProps = CustomComboBoxProps<RoutingTree> & { multi?: false };\ntype MultiSelectProps = Omit<ComponentProps<typeof MultiCombobox<string>>, 'options' | 'loading' | 'onChange'> & {\n  multi: true;\n  onChange: (trees: RoutingTree[]) => void;\n};\n\nexport type RoutingTreeSelectorProps = SingleSelectProps | MultiSelectProps;\n\n/**\n * Routing Tree Combobox which lists all available notification policy trees.\n *\n * When the `alertingMultiplePolicies` feature toggle is enabled on the backend,\n * this shows all available routing trees. Otherwise, it shows only the default\n * \"user-defined\" tree.\n *\n * The default routing tree (named \"user-defined\") is displayed as \"Default policy\"\n * and is always listed first.\n *\n * Supports both single-select (default) and multi-select modes via the `multi` prop.\n *\n * @example\n * ```tsx\n * // Single select\n * <RoutingTreeSelector\n *   value={selectedTreeName}\n *   onChange={(tree) => setSelectedTree(tree)}\n * />\n *\n * // Multi select\n * <RoutingTreeSelector\n *   multi\n *   value={selectedTreeNames}\n *   onChange={(trees) => setSelectedTrees(trees)}\n * />\n * ```\n */\nfunction RoutingTreeSelector(props: RoutingTreeSelectorProps) {\n  const {\n    currentData: routingTrees,\n    isLoading,\n    isError,\n  } = useListRoutingTrees({}, { refetchOnFocus: true, refetchOnMountOrArgChange: true });\n\n  // Build a lookup map from option value → RoutingTree for resolving onChange\n  const { options, treeLookup } = useMemo(() => {\n    if (!routingTrees?.items) {\n      const empty: { options: Array<ComboboxOption<string>>; treeLookup: Map<string, RoutingTree> } = {\n        options: [],\n        treeLookup: new Map(),\n      };\n      return empty;\n    }\n\n    const lookup = new Map<string, RoutingTree>();\n    const opts: Array<ComboboxOption<string>> = routingTrees.items\n      .map((tree) => {\n        const name = tree.metadata.name ?? '';\n        const isDefault = name === USER_DEFINED_TREE_NAME;\n\n        lookup.set(name, tree);\n\n        return {\n          label: isDefault ? t('alerting.routing-tree-selector.default-policy', 'Default policy') : name,\n          value: name,\n          description: isDefault\n            ? t(\n                'alerting.routing-tree-selector.default-policy-desc',\n                'Routes alerts using the default notification policy tree'\n              )\n            : t('alerting.routing-tree-selector.custom-policy-desc', 'Route alerts through the {{name}} policy tree', {\n                name,\n              }),\n        } satisfies ComboboxOption<string>;\n      })\n      .sort((a, b) => {\n        // Default policy always first\n        if (a.value === USER_DEFINED_TREE_NAME) {\n          return -1;\n        }\n        if (b.value === USER_DEFINED_TREE_NAME) {\n          return 1;\n        }\n        return collator.compare(a.label, b.label);\n      });\n\n    return { options: opts, treeLookup: lookup };\n  }, [routingTrees?.items]);\n\n  if (isError) {\n    return (\n      <Alert\n        severity=\"warning\"\n        title={t('alerting.routing-tree-selector.error', 'Failed to load notification policies')}\n      />\n    );\n  }\n\n  if (props.multi) {\n    const { multi: _, onChange, ...rest } = props;\n\n    const handleChange = (selectedOptions: Array<ComboboxOption<string>>) => {\n      const trees = selectedOptions\n        .map((opt) => treeLookup.get(opt.value))\n        .filter((tree): tree is RoutingTree => tree != null);\n      onChange(trees);\n    };\n\n    // @ts-expect-error TypeScript cannot narrow rest-spread from discriminated unions with conditional width types\n    return <MultiCombobox {...rest} loading={isLoading} options={options} onChange={handleChange} />;\n  }\n\n  const handleChange = (selectedOption: ComboboxOption<string> | null) => {\n    if (selectedOption == null && props.isClearable) {\n      props.onChange(null);\n      return;\n    }\n\n    if (selectedOption) {\n      const tree = treeLookup.get(selectedOption.value);\n      if (!tree) {\n        console.warn(`RoutingTreeSelector: could not find routing tree for value \"${selectedOption.value}\"`);\n        return;\n      }\n\n      props.onChange(tree);\n    }\n  };\n\n  return <Combobox {...props} loading={isLoading} options={options} onChange={handleChange} />;\n}\n\nexport { RoutingTreeSelector };\n"],"names":["handleChange"],"mappings":"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"}