"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getSelectedTimelineIds = exports.StatefulOpenTimelineComponent = exports.StatefulOpenTimeline = void 0; var _react = _interopRequireWildcard(require("react")); var _reactRedux = require("react-redux"); var _rison = require("@kbn/rison"); var _use_rule_from_timeline = require("../../../detections/containers/detection_engine/rules/use_rule_from_timeline"); var _kibana = require("../../../common/lib/kibana"); var _constants = require("../../../../common/constants"); var _use_selector = require("../../../common/hooks/use_selector"); var _timeline = require("../../../../common/types/timeline"); var _timeline2 = require("../../store/timeline"); var _actions = require("../../store/timeline/actions"); var _all = require("../../containers/all"); var _default_headers = require("../timeline/body/column_headers/default_headers"); var _open_timeline = require("./open_timeline"); var _helpers = require("./helpers"); var _open_timeline_modal_body = require("./open_timeline_modal/open_timeline_modal_body"); var _constants2 = require("./constants"); var _use_timeline_types = require("./use_timeline_types"); var _use_timeline_status = require("./use_timeline_status"); var _api = require("../../containers/api"); var _model = require("../../../common/store/sourcerer/model"); var _sourcerer = require("../../../common/containers/sourcerer"); var _use_start_transaction = require("../../../common/lib/apm/use_start_transaction"); var _user_actions = require("../../../common/lib/apm/user_actions"); 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. */ /** Returns a collection of selected timeline ids */ const getSelectedTimelineIds = selectedItems => selectedItems.reduce((validSelections, timelineResult) => timelineResult.savedObjectId != null ? [...validSelections, timelineResult.savedObjectId] : validSelections, []); /** Manages the state (e.g table selection) of the (pure) `OpenTimeline` component */ // eslint-disable-next-line react/display-name exports.getSelectedTimelineIds = getSelectedTimelineIds; const StatefulOpenTimelineComponent = /*#__PURE__*/_react.default.memo(({ closeModalTimeline, defaultPageSize, hideActions = [], isModal = false, importDataModalToggle, onOpenTimeline, setImportDataModalToggle, title }) => { const dispatch = (0, _reactRedux.useDispatch)(); const { startTransaction } = (0, _use_start_transaction.useStartTransaction)(); /** Required by EuiTable for expandable rows: a map of `TimelineResult.savedObjectId` to rendered notes */ const [itemIdToExpandedNotesRowMap, setItemIdToExpandedNotesRowMap] = (0, _react.useState)({}); /** Only query for favorite timelines when true */ const [onlyFavorites, setOnlyFavorites] = (0, _react.useState)(false); /** The requested page of results */ const [pageIndex, setPageIndex] = (0, _react.useState)(0); /** The requested size of each page of search results */ const [pageSize, setPageSize] = (0, _react.useState)(defaultPageSize); /** The current search criteria */ const [search, setSearch] = (0, _react.useState)(''); /** The currently-selected timelines in the table */ const [selectedItems, setSelectedItems] = (0, _react.useState)([]); /** The requested sort direction of the query results */ const [sortDirection, setSortDirection] = (0, _react.useState)(_constants2.DEFAULT_SORT_DIRECTION); /** The requested field to sort on */ const [sortField, setSortField] = (0, _react.useState)(_constants2.DEFAULT_SORT_FIELD); const getTimeline = (0, _react.useMemo)(() => _timeline2.timelineSelectors.getTimelineByIdSelector(), []); const timelineSavedObjectId = (0, _use_selector.useShallowEqualSelector)(state => { var _getTimeline$savedObj, _getTimeline; return (_getTimeline$savedObj = (_getTimeline = getTimeline(state, _timeline.TimelineId.active)) === null || _getTimeline === void 0 ? void 0 : _getTimeline.savedObjectId) !== null && _getTimeline$savedObj !== void 0 ? _getTimeline$savedObj : ''; }); const { dataViewId, selectedPatterns } = (0, _sourcerer.useSourcererDataView)(_model.SourcererScopeName.timeline); const updateTimeline = (0, _react.useMemo)(() => (0, _helpers.dispatchUpdateTimeline)(dispatch), [dispatch]); const updateIsLoading = (0, _react.useCallback)(payload => dispatch((0, _actions.updateIsLoading)(payload)), [dispatch]); const { customTemplateTimelineCount, defaultTimelineCount, elasticTemplateTimelineCount, favoriteCount, fetchAllTimeline, timelines, loading, totalCount, templateTimelineCount } = (0, _all.useGetAllTimeline)(); const { timelineType, timelineTabs, timelineFilters } = (0, _use_timeline_types.useTimelineTypes)({ defaultTimelineCount, templateTimelineCount }); const { timelineStatus, templateTimelineFilter, installPrepackagedTimelines } = (0, _use_timeline_status.useTimelineStatus)({ timelineType, customTemplateTimelineCount, elasticTemplateTimelineCount }); const refetch = (0, _react.useCallback)(() => { fetchAllTimeline({ pageInfo: { pageIndex: pageIndex + 1, pageSize }, search, sort: { sortField: sortField, sortOrder: sortDirection }, onlyUserFavorite: onlyFavorites, timelineType, status: timelineStatus }); }, [fetchAllTimeline, pageIndex, pageSize, search, sortField, sortDirection, timelineType, timelineStatus, onlyFavorites]); /** Invoked when the user presses enters to submit the text in the search input */ const onQueryChange = (0, _react.useCallback)(query => { setSearch(query.queryText.trim()); }, []); /** Focuses the input that filters the field browser */ const focusInput = () => { const elements = document.querySelector(`.${_helpers.OPEN_TIMELINE_CLASS_NAME} input`); if (elements != null) { elements.focus(); } }; /* This feature will be implemented in the near future, so we are keeping it to know what to do */ /** Invoked when the user clicks the action to add the selected timelines to favorites */ // const onAddTimelinesToFavorites: OnAddTimelinesToFavorites = () => { // const { addTimelinesToFavorites } = this.props; // const { selectedItems } = this.state; // if (addTimelinesToFavorites != null) { // addTimelinesToFavorites(getSelectedTimelineIds(selectedItems)); // TODO: it's not possible to clear the selection state of the newly-favorited // items, because we can't pass the selection state as props to the table. // See: https://github.com/elastic/eui/issues/1077 // TODO: the query must re-execute to show the results of the mutation // } // }; const deleteTimelines = (0, _react.useCallback)(async timelineIds => { startTransaction({ name: timelineIds.length > 1 ? _user_actions.TIMELINE_ACTIONS.BULK_DELETE : _user_actions.TIMELINE_ACTIONS.DELETE }); if (timelineIds.includes(timelineSavedObjectId)) { dispatch((0, _actions.createTimeline)({ id: _timeline.TimelineId.active, columns: _default_headers.defaultHeaders, dataViewId, indexNames: selectedPatterns, show: false })); } await (0, _api.deleteTimelinesByIds)(timelineIds); refetch(); }, [startTransaction, timelineSavedObjectId, refetch, dispatch, dataViewId, selectedPatterns]); const onDeleteOneTimeline = (0, _react.useCallback)(async timelineIds => { // The type for `deleteTimelines` is incorrect, it returns a Promise await deleteTimelines(timelineIds); }, [deleteTimelines]); /** Invoked when the user clicks the action to delete the selected timelines */ const onDeleteSelected = (0, _react.useCallback)(async () => { // The type for `deleteTimelines` is incorrect, it returns a Promise await deleteTimelines(getSelectedTimelineIds(selectedItems)); // NOTE: we clear the selection state below, but if the server fails to // delete a timeline, it will remain selected in the table: resetSelectionState(); // TODO: the query must re-execute to show the results of the deletion // eslint-disable-next-line react-hooks/exhaustive-deps }, [selectedItems, deleteTimelines]); /** Invoked when the user selects (or de-selects) timelines */ const onSelectionChange = (0, _react.useCallback)(newSelectedItems => { setSelectedItems(newSelectedItems); // <-- this is NOT passed down as props to the table: https://github.com/elastic/eui/issues/1077 }, []); /** Invoked by the EUI table implementation when the user interacts with the table (i.e. to update sorting) */ const onTableChange = (0, _react.useCallback)(({ page, sort }) => { const { index, size } = page; const { field, direction } = sort; setPageIndex(index); setPageSize(size); setSortDirection(direction); setSortField(field); }, []); /** Invoked when the user toggles the option to only view favorite timelines */ const onToggleOnlyFavorites = (0, _react.useCallback)(() => { setOnlyFavorites(!onlyFavorites); }, [onlyFavorites]); /** Invoked when the user toggles the expansion or collapse of inline notes in a table row */ const onToggleShowNotes = (0, _react.useCallback)(newItemIdToExpandedNotesRowMap => { setItemIdToExpandedNotesRowMap(newItemIdToExpandedNotesRowMap); }, []); const { navigateTo } = (0, _kibana.useNavigation)(); const onCreateRule = (0, _react.useCallback)(savedObjectId => navigateTo({ deepLinkId: _constants.SecurityPageName.rulesCreate, path: `?${_use_rule_from_timeline.RULE_FROM_TIMELINE_URL_PARAM}=${(0, _rison.encode)(savedObjectId)}` }), [navigateTo]); const onCreateRuleFromEql = (0, _react.useCallback)(savedObjectId => navigateTo({ deepLinkId: _constants.SecurityPageName.rulesCreate, path: `?${_use_rule_from_timeline.RULE_FROM_EQL_URL_PARAM}=${(0, _rison.encode)(savedObjectId)}` }), [navigateTo]); /** Resets the selection state such that all timelines are unselected */ const resetSelectionState = (0, _react.useCallback)(() => { setSelectedItems([]); }, []); const openTimeline = (0, _react.useCallback)(({ duplicate, timelineId, timelineType: timelineTypeToOpen }) => { if (duplicate) { startTransaction({ name: _user_actions.TIMELINE_ACTIONS.DUPLICATE }); } if (isModal && closeModalTimeline != null) { closeModalTimeline(); } (0, _helpers.queryTimelineById)({ duplicate, onOpenTimeline, timelineId, timelineType: timelineTypeToOpen, updateIsLoading, updateTimeline }); }, // eslint-disable-next-line react-hooks/exhaustive-deps [updateIsLoading, updateTimeline]); (0, _react.useEffect)(() => { focusInput(); }, []); (0, _react.useEffect)(() => { const fetchData = async () => { await installPrepackagedTimelines(); refetch(); }; fetchData(); }, [refetch, installPrepackagedTimelines]); return !isModal ? /*#__PURE__*/_react.default.createElement(_open_timeline.OpenTimeline, { "data-test-subj": 'open-timeline', deleteTimelines: onDeleteOneTimeline, defaultPageSize: defaultPageSize, favoriteCount: favoriteCount, isLoading: loading, itemIdToExpandedNotesRowMap: itemIdToExpandedNotesRowMap, importDataModalToggle: importDataModalToggle, onAddTimelinesToFavorites: undefined, onCreateRule: onCreateRule, onCreateRuleFromEql: onCreateRuleFromEql, onDeleteSelected: onDeleteSelected, onlyFavorites: onlyFavorites, onOpenTimeline: openTimeline, onQueryChange: onQueryChange, onSelectionChange: onSelectionChange, onTableChange: onTableChange, onToggleOnlyFavorites: onToggleOnlyFavorites, onToggleShowNotes: onToggleShowNotes, pageIndex: pageIndex, pageSize: pageSize, query: search, refetch: refetch, searchResults: timelines, setImportDataModalToggle: setImportDataModalToggle, selectedItems: selectedItems, sortDirection: sortDirection, sortField: sortField, templateTimelineFilter: templateTimelineFilter, timelineType: timelineType, timelineStatus: timelineStatus, timelineFilter: timelineTabs, title: title, totalSearchResultsCount: totalCount }) : /*#__PURE__*/_react.default.createElement(_open_timeline_modal_body.OpenTimelineModalBody, { "data-test-subj": 'open-timeline-modal', deleteTimelines: onDeleteOneTimeline, defaultPageSize: defaultPageSize, favoriteCount: favoriteCount, hideActions: hideActions, isLoading: loading, itemIdToExpandedNotesRowMap: itemIdToExpandedNotesRowMap, onAddTimelinesToFavorites: undefined, onlyFavorites: onlyFavorites, onOpenTimeline: openTimeline, onQueryChange: onQueryChange, onSelectionChange: onSelectionChange, onTableChange: onTableChange, onToggleOnlyFavorites: onToggleOnlyFavorites, onToggleShowNotes: onToggleShowNotes, pageIndex: pageIndex, pageSize: pageSize, query: search, searchResults: timelines, selectedItems: selectedItems, sortDirection: sortDirection, sortField: sortField, templateTimelineFilter: templateTimelineFilter, timelineType: timelineType, timelineStatus: timelineStatus, timelineFilter: timelineFilters, title: title, totalSearchResultsCount: totalCount }); }); exports.StatefulOpenTimelineComponent = StatefulOpenTimelineComponent; const StatefulOpenTimeline = /*#__PURE__*/_react.default.memo(StatefulOpenTimelineComponent); exports.StatefulOpenTimeline = StatefulOpenTimeline;