"use strict";

Object.defineProperty(exports, "__esModule", {
  value: true
});
exports.Editor = void 0;
var _eui = require("@elastic/eui");
var _i18n = require("@kbn/i18n");
var _lodash = require("lodash");
var _lzString = require("lz-string");
var _queryString = require("query-string");
var _react = _interopRequireWildcard(require("react"));
var _public = require("@kbn/es-ui-shared-plugin/public");
var _components = require("../../../../components");
var _contexts = require("../../../../contexts");
var _hooks = require("../../../../hooks");
var senseEditor = _interopRequireWildcard(require("../../../../models/sense_editor"));
var _console_menu_actions = require("../console_menu_actions");
var _subscribe_console_resize_checker = require("../subscribe_console_resize_checker");
var _apply_editor_settings = require("./apply_editor_settings");
var _keyboard_shortcuts = require("./keyboard_shortcuts");
var _services = require("../../../../../services");
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 and the Server Side Public License, v 1; you may not use this file except
 * in compliance with, at your election, the Elastic License 2.0 or the Server
 * Side Public License, v 1.
 */

const {
  useUIAceKeyboardMode
} = _public.ace;
const abs = {
  position: 'absolute',
  top: '0',
  left: '0',
  bottom: '0',
  right: '0'
};
const DEFAULT_INPUT_VALUE = `# Click the Variables button, above, to create your own variables.
GET \${exampleVariable1} // _search
{
  "query": {
    "\${exampleVariable2}": {} // match_all
  }
}`;
const inputId = 'ConAppInputTextarea';
function EditorUI({
  initialTextValue,
  setEditorInstance
}) {
  const {
    services: {
      history,
      notifications,
      settings: settingsService,
      esHostService,
      http,
      autocompleteInfo,
      storage
    },
    docLinkVersion
  } = (0, _contexts.useServicesContext)();
  const {
    settings
  } = (0, _contexts.useEditorReadContext)();
  const setInputEditor = (0, _hooks.useSetInputEditor)();
  const sendCurrentRequest = (0, _hooks.useSendCurrentRequest)();
  const saveCurrentTextObject = (0, _hooks.useSaveCurrentTextObject)();
  const editorRef = (0, _react.useRef)(null);
  const editorInstanceRef = (0, _react.useRef)(null);
  const [textArea, setTextArea] = (0, _react.useState)(null);
  useUIAceKeyboardMode(textArea, settings.isAccessibilityOverlayEnabled);
  const openDocumentation = (0, _react.useCallback)(async () => {
    const documentation = await (0, _console_menu_actions.getDocumentation)(editorInstanceRef.current, docLinkVersion);
    if (!documentation) {
      return;
    }
    window.open(documentation, '_blank');
  }, [docLinkVersion]);
  (0, _react.useEffect)(() => {
    editorInstanceRef.current = senseEditor.create(editorRef.current);
    const editor = editorInstanceRef.current;
    const textareaElement = editorRef.current.querySelector('textarea');
    if (textareaElement) {
      textareaElement.setAttribute('id', inputId);
      textareaElement.setAttribute('data-test-subj', 'console-textarea');
    }
    const readQueryParams = () => {
      const [, queryString] = (window.location.hash || '').split('?');
      return (0, _queryString.parse)(queryString || '', {
        sort: false
      });
    };
    const loadBufferFromRemote = url => {
      const coreEditor = editor.getCoreEditor();
      // Normalize and encode the URL to avoid issues with spaces and other special characters.
      const encodedUrl = new URL(url).toString();
      if (/^https?:\/\//.test(encodedUrl)) {
        const loadFrom = {
          url,
          // Having dataType here is required as it doesn't allow jQuery to `eval` content
          // coming from the external source thereby preventing XSS attack.
          dataType: 'text',
          kbnXsrfToken: false
        };
        if (/https?:\/\/api\.github\.com/.test(url)) {
          loadFrom.headers = {
            Accept: 'application/vnd.github.v3.raw'
          };
        }

        // Fire and forget.
        $.ajax(loadFrom).done(async data => {
          // when we load data from another Api we also must pass history
          await editor.update(`${initialTextValue}\n ${data}`, true);
          editor.moveToNextRequestEdge(false);
          coreEditor.clearSelection();
          editor.highlightCurrentRequestsAndUpdateActionBar();
          coreEditor.getContainer().focus();
        });
      }

      // If we have a data URI instead of HTTP, LZ-decode it. This enables
      // opening requests in Console from anywhere in Kibana.
      if (/^data:/.test(url)) {
        const data = (0, _lzString.decompressFromEncodedURIComponent)(url.replace(/^data:text\/plain,/, ''));

        // Show a toast if we have a failure
        if (data === null || data === '') {
          notifications.toasts.addWarning(_i18n.i18n.translate('console.loadFromDataUriErrorMessage', {
            defaultMessage: 'Unable to load data from the load_from query parameter in the URL'
          }));
          return;
        }
        editor.update(data, true);
        editor.moveToNextRequestEdge(false);
        coreEditor.clearSelection();
        editor.highlightCurrentRequestsAndUpdateActionBar();
        coreEditor.getContainer().focus();
      }
    };

    // Support for loading a console snippet from a remote source, like support docs.
    const onHashChange = (0, _lodash.debounce)(() => {
      const {
        load_from: url
      } = readQueryParams();
      if (!url) {
        return;
      }
      loadBufferFromRemote(url);
    }, 200);
    window.addEventListener('hashchange', onHashChange);
    const initialQueryParams = readQueryParams();
    if (initialQueryParams.load_from) {
      loadBufferFromRemote(initialQueryParams.load_from);
    } else {
      editor.update(initialTextValue || DEFAULT_INPUT_VALUE);
    }
    function setupAutosave() {
      let timer;
      const saveDelay = 500;
      editor.getCoreEditor().on('change', () => {
        if (timer) {
          clearTimeout(timer);
        }
        timer = window.setTimeout(saveCurrentState, saveDelay);
      });
    }
    function saveCurrentState() {
      try {
        const content = editor.getCoreEditor().getValue();
        saveCurrentTextObject(content);
      } catch (e) {
        // Ignoring saving error
      }
    }
    function restoreFolds() {
      if (editor) {
        const foldRanges = storage.get(_services.StorageKeys.FOLDS, []);
        editor.getCoreEditor().addFoldsAtRanges(foldRanges);
      }
    }
    restoreFolds();
    function saveFoldsOnChange() {
      if (editor) {
        editor.getCoreEditor().on('changeFold', () => {
          const foldRanges = editor.getCoreEditor().getAllFoldRanges();
          storage.set(_services.StorageKeys.FOLDS, foldRanges);
        });
      }
    }
    saveFoldsOnChange();
    setInputEditor(editor);
    setTextArea(editorRef.current.querySelector('textarea'));
    autocompleteInfo.retrieve(settingsService, settingsService.getAutocomplete());
    const unsubscribeResizer = (0, _subscribe_console_resize_checker.subscribeResizeChecker)(editorRef.current, editor);
    setupAutosave();
    return () => {
      unsubscribeResizer();
      autocompleteInfo.clearSubscriptions();
      window.removeEventListener('hashchange', onHashChange);
      if (editorInstanceRef.current) {
        var _editorInstanceRef$cu;
        // Close autocomplete popup on unmount
        (_editorInstanceRef$cu = editorInstanceRef.current) === null || _editorInstanceRef$cu === void 0 ? void 0 : _editorInstanceRef$cu.getCoreEditor().detachCompleter();
        editorInstanceRef.current.getCoreEditor().destroy();
      }
    };
  }, [notifications.toasts, saveCurrentTextObject, initialTextValue, history, setInputEditor, settingsService, http, autocompleteInfo, storage]);
  (0, _react.useEffect)(() => {
    const {
      current: editor
    } = editorInstanceRef;
    (0, _apply_editor_settings.applyCurrentSettings)(editor.getCoreEditor(), settings);
    // Preserve legacy focus behavior after settings have updated.
    editor.getCoreEditor().getContainer().focus();
  }, [settings]);
  (0, _react.useEffect)(() => {
    const {
      isKeyboardShortcutsEnabled
    } = settings;
    if (isKeyboardShortcutsEnabled) {
      (0, _keyboard_shortcuts.registerCommands)({
        senseEditor: editorInstanceRef.current,
        sendCurrentRequest,
        openDocumentation
      });
    }
  }, [openDocumentation, settings, sendCurrentRequest]);
  (0, _react.useEffect)(() => {
    const {
      current: editor
    } = editorInstanceRef;
    if (editor) {
      setEditorInstance(editor);
    }
  }, [setEditorInstance]);
  return /*#__PURE__*/_react.default.createElement("div", {
    style: abs,
    "data-test-subj": "console-application",
    className: "conApp"
  }, /*#__PURE__*/_react.default.createElement("div", {
    className: "conApp__editor"
  }, /*#__PURE__*/_react.default.createElement("ul", {
    className: "conApp__autoComplete",
    id: "autocomplete"
  }), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, {
    className: "conApp__editorActions",
    id: "ConAppEditorActions",
    gutterSize: "none",
    responsive: false
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, null, /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, {
    content: _i18n.i18n.translate('console.sendRequestButtonTooltip', {
      defaultMessage: 'Click to send request'
    })
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiLink, {
    color: "success",
    onClick: sendCurrentRequest,
    "data-test-subj": "sendRequestButton",
    "aria-label": _i18n.i18n.translate('console.sendRequestButtonTooltip', {
      defaultMessage: 'Click to send request'
    })
  }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, {
    type: "playFilled"
  })))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, null, /*#__PURE__*/_react.default.createElement(_components.ConsoleMenu, {
    getCurl: () => {
      return editorInstanceRef.current.getRequestsAsCURL(esHostService.getHost());
    },
    getDocumentation: () => {
      return (0, _console_menu_actions.getDocumentation)(editorInstanceRef.current, docLinkVersion);
    },
    autoIndent: event => {
      (0, _console_menu_actions.autoIndent)(editorInstanceRef.current, event);
    },
    notifications: notifications
  }))), /*#__PURE__*/_react.default.createElement(_eui.EuiScreenReaderOnly, null, /*#__PURE__*/_react.default.createElement("label", {
    htmlFor: inputId
  }, _i18n.i18n.translate('console.inputTextarea', {
    defaultMessage: 'Dev Tools Console'
  }))), /*#__PURE__*/_react.default.createElement("div", {
    ref: editorRef,
    id: "ConAppEditor",
    className: "conApp__editorContent",
    "data-test-subj": "request-editor"
  })));
}
const Editor = /*#__PURE__*/_react.default.memo(EditorUI);
exports.Editor = Editor;