"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.Flyout = void 0; var _defineProperty2 = _interopRequireDefault(require("@babel/runtime/helpers/defineProperty")); var _react = _interopRequireWildcard(require("react")); var _lodash = require("lodash"); var _eui = require("@elastic/eui"); var _i18n = require("@kbn/i18n"); var _i18nReact = require("@kbn/i18n-react"); var _lib = require("../../../lib"); var _overwrite_modal = require("./overwrite_modal"); var _import_mode_control = require("./import_mode_control"); var _import_summary = require("./import_summary"); 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 CREATE_NEW_COPIES_DEFAULT = false; const OVERWRITE_ALL_DEFAULT = true; const getErrorMessage = e => { var _e$body, _e$body2; const errorMessage = (_e$body = e.body) !== null && _e$body !== void 0 && _e$body.error && (_e$body2 = e.body) !== null && _e$body2 !== void 0 && _e$body2.message ? `${e.body.error}: ${e.body.message}` : e.message; return _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.importFileErrorMessage', { defaultMessage: 'The file could not be processed due to error: "{error}"', values: { error: errorMessage } }); }; class Flyout extends _react.Component { constructor(props) { super(props); (0, _defineProperty2.default)(this, "fetchIndexPatterns", async () => { var _await$this$props$dat; const indexPatterns = (_await$this$props$dat = await this.props.dataViews.getCache()) === null || _await$this$props$dat === void 0 ? void 0 : _await$this$props$dat.map(savedObject => ({ id: savedObject.id, title: savedObject.attributes.title })); this.setState({ indexPatterns }); }); (0, _defineProperty2.default)(this, "changeImportMode", importMode => { this.setState(() => ({ importMode })); }); (0, _defineProperty2.default)(this, "setImportFile", files => { if (!files || !files[0]) { this.setState({ file: undefined }); return; } const file = files[0]; this.setState({ file }); }); /** * Import * * Does the initial import of a file, resolveImportErrors then handles errors and retries */ (0, _defineProperty2.default)(this, "import", async () => { const { http } = this.props; const { file, importMode } = this.state; if (file === undefined) { this.setState({ status: 'error', error: 'missing_file' }); return; } this.setState({ status: 'loading', error: undefined }); // Import the file try { const response = await (0, _lib.importFile)(http, file, importMode); this.setState((0, _lib.processImportResponse)(response), () => { var _this$state$unmatched; // Resolve import errors right away if there's no index patterns to match // This will ask about overwriting each object, etc if (((_this$state$unmatched = this.state.unmatchedReferences) === null || _this$state$unmatched === void 0 ? void 0 : _this$state$unmatched.length) === 0) { this.resolveImportErrors(); } }); } catch (e) { this.setState({ status: 'error', error: getErrorMessage(e) }); return; } }); /** * Get Conflict Resolutions * * Function iterates through the objects, displays a modal for each asking the user if they wish to overwrite it or not. * * @param {array} failures List of objects to request the user if they wish to overwrite it * @return {Promise} An object with the key being "type:id" and value the resolution chosen by the user */ (0, _defineProperty2.default)(this, "getConflictResolutions", async failures => { const resolutions = {}; for (const conflict of failures) { const [overwrite, destinationId] = await new Promise(done => { this.setState({ conflictingRecord: { conflict, done } }); }); if (overwrite) { const { type, id } = conflict.obj; resolutions[`${type}:${id}`] = { retry: true, options: { overwrite: true, ...(destinationId && { destinationId }) } }; } this.setState({ conflictingRecord: undefined }); } return resolutions; }); /** * Resolve Import Errors * * Function goes through the failedImports and tries to resolve the issues. */ (0, _defineProperty2.default)(this, "resolveImportErrors", async () => { this.setState({ error: undefined, status: 'loading', loadingMessage: undefined }); try { const updatedState = await (0, _lib.resolveImportErrors)({ http: this.props.http, state: this.state, getConflictResolutions: this.getConflictResolutions }); this.setState(updatedState); } catch (e) { this.setState({ status: 'error', error: getErrorMessage(e) }); } }); (0, _defineProperty2.default)(this, "onIndexChanged", (id, e) => { const value = e.target.value; this.setState(state => { var _state$unmatchedRefer; const conflictIndex = (_state$unmatchedRefer = state.unmatchedReferences) === null || _state$unmatchedRefer === void 0 ? void 0 : _state$unmatchedRefer.findIndex(conflict => conflict.existingIndexPatternId === id); if (conflictIndex === undefined || conflictIndex === -1) { return state; } return { unmatchedReferences: [...state.unmatchedReferences.slice(0, conflictIndex), { ...state.unmatchedReferences[conflictIndex], newIndexPatternId: value }, ...state.unmatchedReferences.slice(conflictIndex + 1)] }; }); }); this.state = { unmatchedReferences: undefined, unmatchedReferencesTablePagination: { pageIndex: 0, pageSize: 5 }, conflictingRecord: undefined, error: undefined, file: undefined, importCount: 0, indexPatterns: undefined, importMode: { createNewCopies: CREATE_NEW_COPIES_DEFAULT, overwrite: OVERWRITE_ALL_DEFAULT }, loadingMessage: undefined, status: 'idle' }; } componentDidMount() { this.fetchIndexPatterns(); } get hasUnmatchedReferences() { return this.state.unmatchedReferences && this.state.unmatchedReferences.length > 0; } get resolutions() { return this.state.unmatchedReferences.reduce((accum, { existingIndexPatternId, newIndexPatternId }) => { if (newIndexPatternId) { accum.push({ oldId: existingIndexPatternId, newId: newIndexPatternId }); } return accum; }, []); } renderUnmatchedReferences() { const { unmatchedReferences, unmatchedReferencesTablePagination: tablePagination } = this.state; if (!unmatchedReferences) { return null; } const columns = [{ field: 'existingIndexPatternId', name: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdName', { defaultMessage: 'ID' }), description: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnIdDescription', { defaultMessage: 'ID of the data view' }), sortable: true }, { field: 'list', name: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountName', { defaultMessage: 'Count' }), description: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnCountDescription', { defaultMessage: 'How many affected objects' }), render: list => { return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, list.length); } }, { field: 'list', name: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsName', { defaultMessage: 'Sample of affected objects' }), description: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnSampleOfAffectedObjectsDescription', { defaultMessage: 'Sample of affected objects' }), render: list => { return /*#__PURE__*/_react.default.createElement("ul", { style: { listStyle: 'none' } }, (0, _lodash.take)(list, 3).map((obj, key) => /*#__PURE__*/_react.default.createElement("li", { key: key }, obj.title))); } }, { field: 'existingIndexPatternId', name: _i18n.i18n.translate('savedObjectsManagement.objectsTable.flyout.renderConflicts.columnNewIndexPatternName', { defaultMessage: 'New data view' }), render: id => { var _unmatchedReferences$, _unmatchedReferences$2; const options = [{ text: '-- Skip Import --', value: '' }, ...this.state.indexPatterns.map(indexPattern => ({ text: indexPattern.title, value: indexPattern.id, 'data-test-subj': `indexPatternOption-${indexPattern.title}` }))]; const selectedValue = (_unmatchedReferences$ = unmatchedReferences === null || unmatchedReferences === void 0 ? void 0 : (_unmatchedReferences$2 = unmatchedReferences.find(unmatchedRef => unmatchedRef.existingIndexPatternId === id)) === null || _unmatchedReferences$2 === void 0 ? void 0 : _unmatchedReferences$2.newIndexPatternId) !== null && _unmatchedReferences$ !== void 0 ? _unmatchedReferences$ : ''; return /*#__PURE__*/_react.default.createElement(_eui.EuiSelect, { value: selectedValue, "data-test-subj": `managementChangeIndexSelection-${id}`, onChange: e => this.onIndexChanged(id, e), options: options }); } }]; const pagination = { ...tablePagination, pageSizeOptions: [5, 10, 25] }; return /*#__PURE__*/_react.default.createElement(_eui.EuiInMemoryTable, { items: unmatchedReferences, columns: columns, pagination: pagination, onTableChange: ({ page }) => { if (page) { this.setState({ unmatchedReferencesTablePagination: { pageSize: page.size, pageIndex: page.index } }); } } }); } renderError() { const { error, status } = this.state; if (status !== 'error') { return null; } return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, { title: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.errorCalloutTitle", defaultMessage: "Sorry, there was an error" }), color: "danger" }, /*#__PURE__*/_react.default.createElement("p", { "data-test-subj": "importSavedObjectsErrorText" }, error)), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "s" })); } renderBody() { const { allowedTypes, showPlainSpinner } = this.props; const { status, loadingMessage, failedImports = [], successfulImports = [], importMode, importWarnings } = this.state; if (status === 'loading') { return /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { justifyContent: "spaceAround" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, showPlainSpinner ? /*#__PURE__*/_react.default.createElement(_eui.EuiLoadingSpinner, { size: "xl" }) : /*#__PURE__*/_react.default.createElement(_eui.EuiLoadingElastic, { size: "xl" }), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "m" }), /*#__PURE__*/_react.default.createElement(_eui.EuiText, null, /*#__PURE__*/_react.default.createElement("p", null, loadingMessage)))); } // Import summary for completed import if (status === 'success') { return /*#__PURE__*/_react.default.createElement(_import_summary.ImportSummary, { basePath: this.props.http.basePath, failedImports: failedImports, successfulImports: successfulImports, importWarnings: importWarnings !== null && importWarnings !== void 0 ? importWarnings : [], allowedTypes: allowedTypes }); } // Failed imports if (this.hasUnmatchedReferences) { return this.renderUnmatchedReferences(); } return /*#__PURE__*/_react.default.createElement(_eui.EuiForm, null, /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, { fullWidth: true, label: /*#__PURE__*/_react.default.createElement(_eui.EuiTitle, { size: "xs" }, /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.selectFileToImportFormRowLabel", defaultMessage: "Select a file to import" }))) }, /*#__PURE__*/_react.default.createElement(_eui.EuiFilePicker, { accept: ".ndjson", fullWidth: true, initialPromptText: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.importPromptText", defaultMessage: "Import" }), onChange: this.setImportFile })), /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, { fullWidth: true }, /*#__PURE__*/_react.default.createElement(_import_mode_control.ImportModeControl, { initialValues: importMode, updateSelection: newValues => this.changeImportMode(newValues) }))); } renderFooter() { const { status, file } = this.state; const { done, close } = this.props; let confirmButton; if (status === 'success') { confirmButton = /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { onClick: done, size: "s", fill: true, "data-test-subj": "importSavedObjectsDoneBtn" }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmButtonLabel", defaultMessage: "Done" })); } else if (this.hasUnmatchedReferences) { confirmButton = /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { onClick: this.resolveImportErrors, size: "s", fill: true, isLoading: status === 'loading', "data-test-subj": "importSavedObjectsConfirmBtn" }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.importSuccessful.confirmAllChangesButtonLabel", defaultMessage: "Confirm all changes" })); } else { confirmButton = /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { onClick: this.import, size: "s", fill: true, isDisabled: file === undefined, isLoading: status === 'loading', "data-test-subj": "importSavedObjectsImportBtn" }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.import.confirmButtonLabel", defaultMessage: "Import" })); } return /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { justifyContent: "spaceBetween" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiButtonEmpty, { onClick: close, size: "s", disabled: status === 'loading' || status === 'success', "data-test-subj": "importSavedObjectsCancelBtn" }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.import.cancelButtonLabel", defaultMessage: "Cancel" }))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, confirmButton)); } renderSubheader() { if (this.state.status === 'loading' || this.state.status === 'success') { return null; } let indexPatternConflictsWarning; if (this.hasUnmatchedReferences) { indexPatternConflictsWarning = /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, { "data-test-subj": "importSavedObjectsConflictsWarning", title: /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsTitle", defaultMessage: "Data Views Conflicts" }), color: "warning", iconType: "help" }, /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsDescription", defaultMessage: "The following saved objects use data views that do not exist. Please select the data views you'd like re-associated with them. You can {indexPatternLink} if necessary.", values: { indexPatternLink: /*#__PURE__*/_react.default.createElement(_eui.EuiLink, { href: this.props.newIndexPatternUrl }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.indexPatternConflictsCalloutLinkText", defaultMessage: "create a new data view" })) } }))); } if (!indexPatternConflictsWarning) { return null; } return /*#__PURE__*/_react.default.createElement(_react.Fragment, null, indexPatternConflictsWarning && /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "s" }), indexPatternConflictsWarning)); } render() { const { close, allowedTypes } = this.props; let confirmOverwriteModal; const { conflictingRecord } = this.state; if (conflictingRecord) { const { conflict } = conflictingRecord; const onFinish = (overwrite, destinationId) => conflictingRecord.done([overwrite, destinationId]); confirmOverwriteModal = /*#__PURE__*/_react.default.createElement(_overwrite_modal.OverwriteModal, { conflict, onFinish, allowedTypes }); } return /*#__PURE__*/_react.default.createElement(_eui.EuiFlyout, { onClose: close, size: "s", "data-test-subj": "importSavedObjectsFlyout" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlyoutHeader, { hasBorder: true }, /*#__PURE__*/_react.default.createElement(_eui.EuiTitle, { size: "m" }, /*#__PURE__*/_react.default.createElement("h2", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "savedObjectsManagement.objectsTable.flyout.importSavedObjectTitle", defaultMessage: "Import saved objects" })))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlyoutBody, null, this.renderSubheader(), this.renderError(), this.renderBody()), /*#__PURE__*/_react.default.createElement(_eui.EuiFlyoutFooter, null, this.renderFooter()), confirmOverwriteModal); } } exports.Flyout = Flyout;