"use strict";

var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.AgentUpgradeAgentModal = void 0;
var _react = _interopRequireWildcard(require("react"));
var _i18n = require("@kbn/i18n");
var _eui = require("@elastic/eui");
var _i18nReact = require("@kbn/i18n-react");
var _gt = _interopRequireDefault(require("semver/functions/gt"));
var _lt = _interopRequireDefault(require("semver/functions/lt"));
var _services = require("../../../../../../../common/services");
var _get_min_max_version = require("../../../../../../../common/services/get_min_max_version");
var _agent_status = require("../../../../../../../common/services/agent_status");
var _hooks = require("../../../../hooks");
var _constants = require("./constants");
var _hooks2 = require("./hooks");
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
/*
 * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
 * or more contributor license agreements. Licensed under the Elastic License
 * 2.0; you may not use this file except in compliance with the Elastic License
 * 2.0.
 */

const getVersion = version => {
  var _version$;
  return (_version$ = version[0]) === null || _version$ === void 0 ? void 0 : _version$.value;
};
function isVersionUnsupported(version) {
  if (!version) {
    return false;
  }
  return (0, _lt.default)(version, _constants.ROLLING_UPGRADE_MINIMUM_SUPPORTED_VERSION);
}
const AgentUpgradeAgentModal = ({
  onClose,
  agents,
  agentCount,
  isScheduled = false,
  isUpdating = false
}) => {
  var _versionOptions$, _config$internal;
  const {
    notifications
  } = (0, _hooks.useStartServices)();
  const kibanaVersion = (0, _hooks.useKibanaVersion)() || '';
  const config = (0, _hooks.useConfig)();
  const [isSubmitting, setIsSubmitting] = (0, _react.useState)(false);
  const [errors, setErrors] = (0, _react.useState)();
  const [availableVersions, setVersions] = (0, _react.useState)([]);
  const isSingleAgent = Array.isArray(agents) && agents.length === 1;
  const isSmallBatch = agentCount <= 10;
  const isAllAgents = agents === '';
  const [updatingAgents, setUpdatingAgents] = (0, _react.useState)(0);
  const [updatingQuery, setUpdatingQuery] = (0, _react.useState)('');
  const QUERY_STUCK_UPDATING = `status:updating AND upgrade_started_at:* AND NOT upgraded_at:* AND upgrade_started_at < now-${_agent_status.AGENT_UPDATING_TIMEOUT_HOURS}h`;
  (0, _react.useEffect)(() => {
    const getStuckUpdatingAgentCount = async agentsOrQuery => {
      let newQuery;
      // find updating agents from array
      if (Array.isArray(agentsOrQuery) && agentsOrQuery.length > 0) {
        if (agentsOrQuery.length === 0) {
          return;
        }
        const newAgents = agentsOrQuery.filter(agent => (0, _agent_status.isStuckInUpdating)(agent));
        const updatingCount = newAgents.length;
        setUpdatingAgents(updatingCount);
        setUpdatingQuery(newAgents);
        return;
      } else if (typeof agentsOrQuery === 'string' && agentsOrQuery !== '') {
        newQuery = [`(${agentsOrQuery})`, QUERY_STUCK_UPDATING].join(' AND ');
      } else {
        newQuery = QUERY_STUCK_UPDATING;
      }
      setUpdatingQuery(newQuery);

      // if selection is a query, do an api call to get updating agents
      try {
        var _res$data$results$upd, _res$data, _res$data$results;
        const res = await (0, _hooks.sendGetAgentStatus)({
          kuery: newQuery
        });
        setUpdatingAgents((_res$data$results$upd = res === null || res === void 0 ? void 0 : (_res$data = res.data) === null || _res$data === void 0 ? void 0 : (_res$data$results = _res$data.results) === null || _res$data$results === void 0 ? void 0 : _res$data$results.updating) !== null && _res$data$results$upd !== void 0 ? _res$data$results$upd : 0);
      } catch (err) {
        return;
      }
    };
    if (!isUpdating) return;
    getStuckUpdatingAgentCount(agents);
  }, [isUpdating, setUpdatingQuery, QUERY_STUCK_UPDATING, agents]);
  (0, _react.useEffect)(() => {
    const getVersions = async () => {
      try {
        var _res$data2;
        const res = await (0, _hooks.sendGetAgentsAvailableVersions)();
        // if the endpoint returns an error, use the fallback versions
        const versionsList = res !== null && res !== void 0 && (_res$data2 = res.data) !== null && _res$data2 !== void 0 && _res$data2.items ? res.data.items : _constants.FALLBACK_VERSIONS;
        setVersions(versionsList);
      } catch (err) {
        return;
      }
    };
    getVersions();
  }, [kibanaVersion]);
  const minVersion = (0, _react.useMemo)(() => {
    if (!Array.isArray(agents)) {
      // when agent is a query, don't set minVersion, so the versions are available to select
      if (typeof agents === 'string') {
        return undefined;
      }
      return (0, _get_min_max_version.getMinVersion)(availableVersions);
    }
    const versions = agents.map(agent => {
      var _agent$local_metadata, _agent$local_metadata2, _agent$local_metadata3;
      return (_agent$local_metadata = agent.local_metadata) === null || _agent$local_metadata === void 0 ? void 0 : (_agent$local_metadata2 = _agent$local_metadata.elastic) === null || _agent$local_metadata2 === void 0 ? void 0 : (_agent$local_metadata3 = _agent$local_metadata2.agent) === null || _agent$local_metadata3 === void 0 ? void 0 : _agent$local_metadata3.version;
    });
    return (0, _get_min_max_version.getMinVersion)(versions);
  }, [agents, availableVersions]);
  const versionOptions = (0, _react.useMemo)(() => {
    const displayVersions = minVersion ? availableVersions.filter(v => (0, _gt.default)(v, minVersion)) : availableVersions;
    const options = displayVersions.map(option => ({
      label: option,
      value: option
    }));
    if (options.length === 0) {
      return [{
        label: '',
        value: ''
      }];
    }
    return options;
  }, [availableVersions, minVersion]);
  const noVersions = !availableVersions || ((_versionOptions$ = versionOptions[0]) === null || _versionOptions$ === void 0 ? void 0 : _versionOptions$.value) === '';
  const maintenanceOptions = _constants.MAINTENANCE_VALUES.map(option => ({
    label: option === 0 ? _i18n.i18n.translate('xpack.fleet.upgradeAgents.noMaintenanceWindowOption', {
      defaultMessage: 'Immediately'
    }) : _i18n.i18n.translate('xpack.fleet.upgradeAgents.hourLabel', {
      defaultMessage: '{option} {count, plural, one {hour} other {hours}}',
      values: {
        option,
        count: option === 1
      }
    }),
    value: option === 0 ? 0 : option * 3600
  }));
  const preselected = [{
    label: kibanaVersion,
    value: kibanaVersion
  }];
  const [selectedVersion, setSelectedVersion] = (0, _react.useState)(preselected);

  // latest agent version might be earlier than kibana version
  const latestAgentVersion = (0, _hooks.useAgentVersion)();
  (0, _react.useEffect)(() => {
    if (latestAgentVersion) {
      setSelectedVersion([{
        label: latestAgentVersion,
        value: latestAgentVersion
      }]);
    }
  }, [latestAgentVersion]);
  const [selectedMaintenanceWindow, setSelectedMaintenanceWindow] = (0, _react.useState)([isSmallBatch ? maintenanceOptions[0] : maintenanceOptions[1]]);
  const {
    startDatetime,
    onChangeStartDateTime,
    initialDatetime,
    minTime,
    maxTime
  } = (0, _hooks2.useScheduleDateTime)();
  async function onSubmit() {
    var _selectedMaintenanceW;
    const version = getVersion(selectedVersion);
    const rolloutOptions = {
      rollout_duration_seconds: selectedMaintenanceWindow.length > 0 && ((_selectedMaintenanceW = selectedMaintenanceWindow[0]) === null || _selectedMaintenanceW === void 0 ? void 0 : _selectedMaintenanceW.value) > 0 ? selectedMaintenanceWindow[0].value : undefined,
      start_time: startDatetime.toISOString()
    };
    try {
      setIsSubmitting(true);
      const getQuery = agentsOrQuery => Array.isArray(agentsOrQuery) ? agentsOrQuery.map(agent => agent.id) : agentsOrQuery;
      const {
        error
      } = isSingleAgent && !isScheduled ? await (0, _hooks.sendPostAgentUpgrade)(agents[0].id, {
        version,
        force: isUpdating
      }) : await (0, _hooks.sendPostBulkAgentUpgrade)({
        version,
        agents: getQuery(isUpdating ? updatingQuery : agents),
        force: isUpdating,
        ...rolloutOptions
      });
      if (error) {
        if ((error === null || error === void 0 ? void 0 : error.statusCode) === 400) {
          setErrors(error === null || error === void 0 ? void 0 : error.message);
        }
        throw error;
      }
      setIsSubmitting(false);
      notifications.toasts.addSuccess(_i18n.i18n.translate('xpack.fleet.upgradeAgents.successNotificationTitle', {
        defaultMessage: 'Upgrading agent(s)'
      }));
      onClose();
    } catch (error) {
      setIsSubmitting(false);
      notifications.toasts.addError(error, {
        title: _i18n.i18n.translate('xpack.fleet.upgradeAgents.fatalErrorNotificationTitle', {
          defaultMessage: 'Error upgrading {count, plural, one {agent} other {{count} agents} =true {all selected agents}}',
          values: {
            count: isAllAgents || agentCount
          }
        })
      });
    }
  }
  const onCreateOption = searchValue => {
    const normalizedSearchValue = searchValue.trim();
    const newOption = {
      label: normalizedSearchValue,
      value: normalizedSearchValue
    };
    setSelectedVersion([newOption]);
  };
  return /*#__PURE__*/_react.default.createElement(_eui.EuiConfirmModal, {
    "data-test-subj": "agentUpgradeModal",
    title: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, isSingleAgent ? isUpdating ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.restartUpgradeSingleTitle",
      defaultMessage: "Restart upgrade"
    }) : /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.upgradeSingleTitle",
      defaultMessage: "Upgrade agent"
    }) : isScheduled ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.scheduleUpgradeMultipleTitle",
      defaultMessage: "Schedule upgrade for {count, plural, one {agent} other {{count} agents} =true {all selected agents}}",
      values: {
        count: isAllAgents || agentCount
      }
    }) : isUpdating ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.restartUpgradeMultipleTitle",
      defaultMessage: "Restart upgrade on {updating} out of {count, plural, one {agent} other {{count} agents} =true {all agents}} stuck in updating",
      values: {
        count: isAllAgents || agentCount,
        updating: updatingAgents
      }
    }) : /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.upgradeMultipleTitle",
      defaultMessage: "Upgrade {count, plural, one {agent} other {{count} agents} =true {all selected agents}}",
      values: {
        count: isAllAgents || agentCount
      }
    })),
    onCancel: onClose,
    onConfirm: onSubmit,
    cancelButtonText: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.cancelButtonLabel",
      defaultMessage: "Cancel"
    }),
    confirmButtonDisabled: isSubmitting || noVersions || isUpdating && updatingAgents === 0,
    confirmButtonText: isSingleAgent ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.confirmSingleButtonLabel",
      defaultMessage: "Upgrade agent"
    }) : isScheduled ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.confirmScheduleMultipleButtonLabel",
      defaultMessage: "Schedule"
    }) : isUpdating ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.restartConfirmMultipleButtonLabel",
      defaultMessage: "Restart upgrade {count, plural, one {agent} other {{count} agents} =true {all selected agents}}",
      values: {
        count: updatingAgents
      }
    }) : /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.confirmMultipleButtonLabel",
      defaultMessage: "Upgrade {count, plural, one {agent} other {{count} agents} =true {all selected agents}}",
      values: {
        count: isAllAgents || agentCount
      }
    })
  }, /*#__PURE__*/_react.default.createElement("p", null, noVersions ? /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
    id: "xpack.fleet.upgradeAgents.noVersionsText",
    defaultMessage: "No selected agents are eligible for an upgrade. Please select one or more eligible agents."
  }) : isSingleAgent ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
    id: "xpack.fleet.upgradeAgents.upgradeSingleDescription",
    defaultMessage: "This action will upgrade the agent running on '{hostName}' to version {version}. This action can not be undone. Are you sure you wish to continue?",
    values: {
      hostName: agents[0].local_metadata.host.hostname,
      version: getVersion(selectedVersion)
    }
  })), isUpdating && /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement("em", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
    id: "xpack.fleet.upgradeAgents.upgradeSingleTimeout"
    // TODO: Add link to docs regarding agent upgrade cooldowns
    ,
    defaultMessage: "Note that you may only restart an upgrade every {minutes} minutes to ensure that the upgrade will not be rolled back.",
    values: {
      minutes: _services.AGENT_UPGRADE_COOLDOWN_IN_MIN
    }
  })))) : /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
    id: "xpack.fleet.upgradeAgents.upgradeMultipleDescription",
    defaultMessage: "This action will upgrade multiple agents to version {version}. This action can not be undone. Are you sure you wish to continue?",
    values: {
      version: getVersion(selectedVersion)
    }
  })), /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, {
    label: _i18n.i18n.translate('xpack.fleet.upgradeAgents.chooseVersionLabel', {
      defaultMessage: 'Upgrade version'
    }),
    fullWidth: true
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiComboBox, {
    "data-test-subj": "agentUpgradeModal.VersionCombobox",
    fullWidth: true,
    singleSelection: {
      asPlainText: true
    },
    options: versionOptions,
    isDisabled: noVersions,
    isClearable: false,
    selectedOptions: selectedVersion,
    onChange: selected => {
      if (!selected.length) {
        return;
      }
      setSelectedVersion(selected);
    },
    onCreateOption: config !== null && config !== void 0 && (_config$internal = config.internal) !== null && _config$internal !== void 0 && _config$internal.onlyAllowAgentUpgradeToKnownVersions ? undefined : onCreateOption,
    customOptionText: "Use custom agent version {searchValue} (not recommended)"
  })), !isSingleAgent && Array.isArray(agents) && agents.some(agent => {
    var _agent$local_metadata4, _agent$local_metadata5, _agent$local_metadata6;
    return isVersionUnsupported((_agent$local_metadata4 = agent.local_metadata) === null || _agent$local_metadata4 === void 0 ? void 0 : (_agent$local_metadata5 = _agent$local_metadata4.elastic) === null || _agent$local_metadata5 === void 0 ? void 0 : (_agent$local_metadata6 = _agent$local_metadata5.agent) === null || _agent$local_metadata6 === void 0 ? void 0 : _agent$local_metadata6.version);
  }) ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, {
    size: "m"
  }), /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, {
    color: "warning",
    title: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, {
      id: "xpack.fleet.upgradeAgents.warningCallout",
      defaultMessage: "Rolling upgrades are only available for Elastic Agent versions {version} and higher",
      values: {
        version: /*#__PURE__*/_react.default.createElement("strong", null, _constants.ROLLING_UPGRADE_MINIMUM_SUPPORTED_VERSION)
      }
    })
  })) : null, isScheduled && /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, {
    size: "m"
  }), /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, {
    label: _i18n.i18n.translate('xpack.fleet.upgradeAgents.startTimeLabel', {
      defaultMessage: 'Scheduled date and time'
    }),
    fullWidth: true
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiDatePicker, {
    "data-test-subj": "agentUpgradeModal.startTimeDatePicker",
    fullWidth: true,
    required: true,
    showTimeSelect: true,
    selected: startDatetime,
    minDate: initialDatetime,
    minTime: minTime,
    maxTime: maxTime,
    onChange: onChangeStartDateTime
  }))), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, {
    size: "m"
  }), !isSingleAgent ? /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, {
    label: /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, {
      gutterSize: "s"
    }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, {
      grow: false
    }, _i18n.i18n.translate('xpack.fleet.upgradeAgents.rolloutPeriodLabel', {
      defaultMessage: 'Rollout period'
    })), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, {
      size: "xs"
    }), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, {
      grow: false
    }, /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, {
      position: "top",
      content: _i18n.i18n.translate('xpack.fleet.upgradeAgents.rolloutPeriodTooltip', {
        defaultMessage: 'Define the rollout period for upgrades to your Elastic Agents. Any agents that are offline during this period will be upgraded when they come back online.'
      })
    }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, {
      type: "iInCircle"
    })))),
    fullWidth: true
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiComboBox, {
    "data-test-subj": "agentUpgradeModal.MaintenanceCombobox",
    fullWidth: true,
    isClearable: false,
    singleSelection: {
      asPlainText: true
    },
    options: maintenanceOptions,
    selectedOptions: selectedMaintenanceWindow,
    onChange: selected => {
      if (!selected.length) {
        return;
      }
      setSelectedMaintenanceWindow(selected);
    }
  })) : null, errors ? /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, {
    size: "s"
  }), /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, {
    color: "danger",
    title: _i18n.i18n.translate('xpack.fleet.upgradeAgents.warningCalloutErrors', {
      defaultMessage: 'Error upgrading the selected {count, plural, one {agent} other {{count} agents}}',
      values: {
        count: isSingleAgent
      }
    })
  })) : null);
};
exports.AgentUpgradeAgentModal = AgentUpgradeAgentModal;