text: import React, { Component } from "react";
  import PropTypes from "prop-types";
  
  import { observable, action, computed, toJS } from "mobx";
  import { observer } from "mobx-react";
  
  import moment from "moment";
  
  import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
  import { faCheck } from "@fortawesome/free-solid-svg-icons/faCheck";
  import { faCheckCircle } from "@fortawesome/free-solid-svg-icons/faCheckCircle";
  import { faSpinner } from "@fortawesome/free-solid-svg-icons/faSpinner";
  import { faExclamationCircle } from "@fortawesome/free-solid-svg-icons/faExclamationCircle";
  
  import { APIGroup } from "Models/API";
  import { AlertStore } from "Stores/AlertStore";
  import {
    SilenceFormStore,
    MatchersFromGroup,
    GenerateAlertmanagerSilenceData,
  } from "Stores/SilenceFormStore";
  import { FetchPost } from "Common/Fetch";
  import { TooltipWrapper } from "Components/TooltipWrapper";
  
  const SubmitState = Object.freeze({
    Idle: "Idle",
    InProgress: "InProgress",
    Done: "Done",
    Failed: "Failed",
  });
  
  const newPendingSilence = (
    group,
    members,
    durationSeconds,
    author,
    commentPrefix
  ) => ({
    payload: GenerateAlertmanagerSilenceData(
      moment.utc(),
      moment.utc().add(durationSeconds, "seconds"),
      MatchersFromGroup(group, [], group.alerts, true),
      author,
      `${
        commentPrefix ? commentPrefix + " " : ""
      }This alert was acknowledged using karma on ${moment.utc().toString()}`
    ),
    membersToTry: members,
    submitState: SubmitState.Idle,
    submitResult: null,
    isDone: false,
    isFailed: false,
    fetch: null,
    error: null,
  });
  
  const AlertAck = observer(
    class AlertAck extends Component {
      static propTypes = {
        alertStore: PropTypes.instanceOf(AlertStore).isRequired,
        silenceFormStore: PropTypes.instanceOf(SilenceFormStore).isRequired,
        group: APIGroup.isRequired,
      };
  
      constructor(props) {
        super(props);
        this.submitState = observable(
          {
            silencesByCluster: {},
            reset() {
              this.silencesByCluster = {};
            },
            pushSilence(cluster, silence) {
              this.silencesByCluster[cluster] = silence;
            },
            markDone(cluster) {
              this.silencesByCluster[cluster].isDone = true;
            },
            markFailed(cluster, err) {
              this.silencesByCluster[cluster].isDone = true;
              this.silencesByCluster[cluster].isFailed = true;
              this.silencesByCluster[cluster].error = err;
            },
            get isIdle() {
              return Object.keys(this.silencesByCluster).length === 0;
            },
            get isInprogress() {
              return (
                Object.values(this.silencesByCluster).filter(
                  (pendingSilence) => pendingSilence.isDone === false
                ).length > 0
              );
            },
            get isDone() {
              return (
                Object.values(this.silencesByCluster).filter(
                  (pendingSilence) => pendingSilence.isDone === true
                ).length > 0
              );
            },
            get isFailed() {
              return (
                Object.values(this.silencesByCluster).filter(
                  (pendingSilence) => pendingSilence.isFailed === true
                ).length > 0
              );
            },
            get errorMessages() {
              return Object.values(this.silencesByCluster)
                .filter((pendingSilence) => pendingSilence.error !== null)
                .map((s) => s.error);
            },
          },
          {
            reset: action.bound,
            pushSilence: action.bound,
            markDone: action.bound,
            markFailed: action.bound,
            isIdle: computed,
            isInprogress: computed,
            isDone: computed,
            isFailed: computed,
            errorMessages: computed,
          }
        );
      }
  
      maybeTryAgainAfterError = (cluster, err) => {
        if (this.submitState.silencesByCluster[cluster].membersToTry.length) {
          this.handleAlertmanagerRequest(cluster);
        } else {
          this.submitState.markFailed(cluster, err);
        }
      };
  
      handleAlertmanagerRequest = (cluster) => {
        const { alertStore } = this.props;
  
        const member = this.submitState.silencesByCluster[
          cluster
        ].membersToTry.pop();
  
        const am = alertStore.data.getAlertmanagerByName(member);
        if (am === undefined) {
          const err = `Alertmanager instance "${member} not found`;
          console.error(err);
          this.maybeTryAgainAfterError(cluster, err);
          return;
        }
  
        this.submitState.silencesByCluster[cluster].fetch = FetchPost(
          `${am.uri}/api/v2/silences`,
          {
            body: JSON.stringify(
              this.submitState.silencesByCluster[cluster].payload
            ),
            credentials: am.corsCredentials,
            headers: {
              "Content-Type": "application/json",
              ...am.headers,
            },
          }
        )
          .then((result) => {
            if (result.ok) {
              return result
                .json()
                .then((r) => this.submitState.markDone(cluster));
            } else {
              result
                .text()
                .then((text) => this.maybeTryAgainAfterError(cluster, text));
            }
          })
          .catch((err) => {
            this.maybeTryAgainAfterError(cluster, err);
          });
      };
  
      onACK = () => {
        const { group, alertStore, silenceFormStore } = this.props;
  
        if (this.submitState.isInprogress || this.submitState.isDone) {
          return;
        }
  
        let author =
          silenceFormStore.data.author !== ""
            ? toJS(silenceFormStore.data.author)
            : toJS(alertStore.settings.values.alertAcknowledgement.author);
  
        if (alertStore.info.authentication.enabled) {
          silenceFormStore.data.author = toJS(
            alertStore.info.authentication.username
          );
          author = alertStore.info.authentication.username;
        }
  
        const alertmanagers = Object.entries(group.alertmanagerCount)
          .filter(([amName, alertCount]) => alertCount > 0)
          .map(([amName, _]) => amName);
        const clusters = Object.entries(
          alertStore.data.clustersWithoutReadOnly
        ).filter(([clusterName, clusterMembers]) =>
          alertmanagers.some((m) => clusterMembers.includes(m))
        );
  
        this.submitState.reset();
        for (const [clusterName, clusterMembers] of clusters) {
          const pendingSilence = newPendingSilence(
            toJS(group),
            toJS(clusterMembers),
            toJS(alertStore.settings.values.alertAcknowledgement.durationSeconds),
            author,
            toJS(alertStore.settings.values.alertAcknowledgement.commentPrefix)
          );
          this.submitState.pushSilence(clusterName, pendingSilence);
          this.handleAlertmanagerRequest(clusterName);
        }
      };
  
      render() {
        const { alertStore } = this.props;
  
        if (alertStore.settings.values.alertAcknowledgement.enabled === false) {
          return null;
        }
  
        const tooltipProps = {};
        if (this.submitState.isFailed) {
          tooltipProps.html = this.submitState.errorMessages[0];
        } else {
          tooltipProps.title =
            "Acknowledge this alert with a short lived silence";
        }
  
        return (
          <TooltipWrapper {...tooltipProps}>
            <span
              className={`badge badge-pill components-label components-label-with-hover px-2 ${
                this.submitState.isFailed
                  ? "badge-warning"
                  : this.submitState.isDone
                  ? "badge-success"
                  : "badge-secondary"
              }`}
              onClick={this.onACK}
            >
              {this.submitState.isIdle ? (
                <FontAwesomeIcon icon={faCheck} fixedWidth />
              ) : this.submitState.isInprogress ? (
                <FontAwesomeIcon icon={faSpinner} fixedWidth spin />
              ) : this.submitState.isFailed ? (
                <FontAwesomeIcon icon={faExclamationCircle} fixedWidth />
              ) : (
                <FontAwesomeIcon icon={faCheckCircle} fixedWidth />
              )}
            </span>
          </TooltipWrapper>
        );
      }
    }
  );
  
  export { AlertAck };
  