import { FC, Ref, CSSProperties, useRef, useState, useCallback } from "react"; import { observer } from "mobx-react-lite"; import { useFloating, shift, offset } from "@floating-ui/react-dom"; import copy from "copy-to-clipboard"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { faCaretDown } from "@fortawesome/free-solid-svg-icons/faCaretDown"; import { faBellSlash } from "@fortawesome/free-solid-svg-icons/faBellSlash"; import { faExternalLinkAlt } from "@fortawesome/free-solid-svg-icons/faExternalLinkAlt"; import { faWrench } from "@fortawesome/free-solid-svg-icons/faWrench"; import { faCopy } from "@fortawesome/free-solid-svg-icons/faCopy"; import type { APIGridT, APIAlertT, APIAlertGroupT, APIAnnotationT, } from "Models/APITypes"; import type { AlertStore } from "Stores/AlertStore"; import { SilenceFormStore, AlertmanagerClustersToOption, } from "Stores/SilenceFormStore"; import { FetchPauser } from "Components/FetchPauser"; import { DropdownSlide } from "Components/Animations/DropdownSlide"; import { DateFromNow } from "Components/DateFromNow"; import { useOnClickOutside } from "Hooks/useOnClickOutside"; import { MenuLink } from "Components/Grid/AlertGrid/AlertGroup/MenuLink"; import { alertToJSON } from "Common/Alert"; const onSilenceClick = ( alertStore: AlertStore, silenceFormStore: SilenceFormStore, group: APIAlertGroupT, alert: APIAlertT ) => { const clusters: { [cluster: string]: string[] } = {}; Object.entries(alertStore.data.clustersWithoutReadOnly).forEach( ([cluster, members]) => { if (alert.alertmanager.map((am) => am.cluster).includes(cluster)) { clusters[cluster] = members; } } ); silenceFormStore.data.resetProgress(); silenceFormStore.data.fillMatchersFromGroup( group, alertStore.settings.values.silenceForm.strip.labels, AlertmanagerClustersToOption(clusters), [alert] ); silenceFormStore.tab.setTab("editor"); silenceFormStore.toggle.show(); }; const MenuContent: FC<{ x: number | null; y: number | null; floating: Ref | null; strategy: CSSProperties["position"]; group: APIAlertGroupT; alert: APIAlertT; afterClick: () => void; alertStore: AlertStore; silenceFormStore: SilenceFormStore; }> = ({ x, y, floating, strategy, group, alert, afterClick, alertStore, silenceFormStore, }) => { const actions: APIAnnotationT[] = [ ...alert.annotations .filter((a) => a.isLink === true) .filter((a) => a.isAction === true), ...group.shared.annotations .filter((a) => a.isLink === true) .filter((a) => a.isAction === true), ]; return (
Alert source links:
{alert.alertmanager.map((am) => ( ))}
{ copy(JSON.stringify(alertToJSON(group, alert))); afterClick(); }} > Copy to clipboard
{actions.length ? ( <>
Actions:
{actions.map((action) => ( ))} ) : null}
{ if (Object.keys(alertStore.data.clustersWithoutReadOnly).length) { onSilenceClick(alertStore, silenceFormStore, group, alert); afterClick(); } }} > Silence this alert
); }; const AlertMenu: FC<{ grid: APIGridT; group: APIAlertGroupT; alert: APIAlertT; alertStore: AlertStore; silenceFormStore: SilenceFormStore; setIsMenuOpen: (isOpen: boolean) => void; }> = observer( ({ grid, group, alert, alertStore, silenceFormStore, setIsMenuOpen }) => { const [isHidden, setIsHidden] = useState(true); const toggle = useCallback(() => { setIsMenuOpen(isHidden); setIsHidden(!isHidden); }, [isHidden, setIsMenuOpen]); const hide = useCallback(() => { setIsHidden(true); setIsMenuOpen(false); }, [setIsMenuOpen]); const rootRef = useRef(null); useOnClickOutside(rootRef, hide, !isHidden); const { x, y, refs, strategy } = useFloating({ placement: "bottom-start", middleware: [shift(), offset(5)], }); return ( ); } ); export { AlertMenu, MenuContent };