"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.default = exports.SessionView = void 0; var _react = _interopRequireWildcard(require("react")); var _eui = require("@elastic/eui"); var _i18nReact = require("@kbn/i18n-react"); var _useLocalStorage = _interopRequireDefault(require("react-use/lib/useLocalStorage")); var _byteSize = _interopRequireDefault(require("byte-size")); var _shared_imports = require("../../shared_imports"); var _process_tree = require("../process_tree"); var _session_view_detail_panel = require("../session_view_detail_panel"); var _session_view_search_bar = require("../session_view_search_bar"); var _session_view_display_options = require("../session_view_display_options"); var _tty_player = require("../tty_player"); var _styles = require("./styles"); var _hooks = require("./hooks"); var _constants = require("../../../common/constants"); var _methods = require("../../methods"); var _translations = require("./translations"); 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. */ /** * The main wrapper component for the session view. */ const SessionView = ({ index, sessionEntityId, sessionStartTime, height, isFullScreen = false, jumpToEntityId, jumpToCursor, investigatedAlertId, loadAlertDetails, canReadPolicyManagement, trackEvent }) => { var _data$pages, _fetchAlertStatus$; // don't engage jumpTo if jumping to session leader. if (jumpToEntityId === sessionEntityId) { jumpToEntityId = undefined; jumpToCursor = undefined; } // track session open telemetry (0, _react.useEffect)(() => { let source = ''; // append 'app' details (which telemtry source is this from?) if (index === _methods.CLOUD_DEFEND_INDEX) { source += 'cloud-defend'; } else if (index === _methods.ENDPOINT_INDEX) { source += 'endpoint'; } else { // any telemetry producers setting process.entry_leader.entity_id will cause sessionview action to appear in timeline tables. source += 'unknown'; } const eventKey = `loaded_from_${source}_${investigatedAlertId ? 'alert' : 'log'}`; trackEvent(eventKey); }, [index, investigatedAlertId, trackEvent]); const [showTTY, setShowTTY] = (0, _react.useState)(false); const [isDetailOpen, setIsDetailOpen] = (0, _react.useState)(false); const [selectedProcess, setSelectedProcess] = (0, _react.useState)(null); const [searchQuery, setSearchQuery] = (0, _react.useState)(''); const [searchResults, setSearchResults] = (0, _react.useState)(null); const [displayOptions, setDisplayOptions] = (0, _useLocalStorage.default)(_constants.LOCAL_STORAGE_DISPLAY_OPTIONS_KEY, { timestamp: true, verboseMode: false }); const [fetchAlertStatus, setFetchAlertStatus] = (0, _react.useState)([]); const [updatedAlertsStatus, setUpdatedAlertsStatus] = (0, _react.useState)({}); const [currentJumpToCursor, setCurrentJumpToCursor] = (0, _react.useState)(jumpToCursor); const [currentJumpToEntityId, setCurrentJumpToEntityId] = (0, _react.useState)(jumpToEntityId); const [currentJumpToOutputEntityId, setCurrentJumpToOutputEntityId] = (0, _react.useState)(''); const styles = (0, _styles.useStyles)({ height, isFullScreen }); const detailPanelCollapseFn = (0, _react.useRef)(() => {}); // to give an indication to the user that there may be more search results if they turn on verbose mode. const showVerboseSearchTooltip = (0, _react.useMemo)(() => { return !!(!(displayOptions !== null && displayOptions !== void 0 && displayOptions.verboseMode) && searchQuery && (searchResults === null || searchResults === void 0 ? void 0 : searchResults.length) === 0); }, [displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.verboseMode, searchResults, searchQuery]); const onProcessSelected = (0, _react.useCallback)(process => { setSelectedProcess(process); }, []); const onJumpToEvent = (0, _react.useCallback)(event => { if (event.process) { const { entity_id: entityId } = event.process; if (entityId !== sessionEntityId) { var _event$kibana; const alert = (_event$kibana = event.kibana) === null || _event$kibana === void 0 ? void 0 : _event$kibana.alert; const cursor = alert ? alert === null || alert === void 0 ? void 0 : alert.original_time : event['@timestamp']; if (cursor) { setCurrentJumpToEntityId(entityId); setCurrentJumpToCursor(cursor); } } setSelectedProcess(null); } }, [sessionEntityId]); const onJumpToOutput = (0, _react.useCallback)(entityId => { setCurrentJumpToOutputEntityId(entityId); setShowTTY(true); }, []); const { data, error, fetchNextPage, hasNextPage, isFetching, fetchPreviousPage, hasPreviousPage, refetch } = (0, _hooks.useFetchSessionViewProcessEvents)(index, sessionEntityId, sessionStartTime, currentJumpToCursor); const { data: alertsData, fetchNextPage: fetchNextPageAlerts, isFetching: isFetchingAlerts, hasNextPage: hasNextPageAlerts, error: alertsError, refetch: refetchAlerts } = (0, _hooks.useFetchSessionViewAlerts)(sessionEntityId, sessionStartTime, investigatedAlertId); const { data: totalTTYOutputBytes, refetch: refetchTotalTTYOutput } = (0, _hooks.useFetchGetTotalIOBytes)(index, sessionEntityId, sessionStartTime); const hasTTYOutput = !!(totalTTYOutputBytes !== null && totalTTYOutputBytes !== void 0 && totalTTYOutputBytes.total); const bytesOfOutput = (0, _react.useMemo)(() => { const { unit, value } = (0, _byteSize.default)((totalTTYOutputBytes === null || totalTTYOutputBytes === void 0 ? void 0 : totalTTYOutputBytes.total) || 0); return { unit, value }; }, [totalTTYOutputBytes === null || totalTTYOutputBytes === void 0 ? void 0 : totalTTYOutputBytes.total]); const onToggleTTY = (0, _react.useCallback)(() => { if (hasTTYOutput) { setShowTTY(!showTTY); trackEvent('tty_loaded'); } else { trackEvent('disabled_tty_clicked'); } }, [hasTTYOutput, showTTY, trackEvent]); const handleRefresh = (0, _react.useCallback)(() => { refetch({ refetchPage: (_page, i, allPages) => allPages.length - 1 === i }); refetchAlerts({ refetchPage: (_page, i, allPages) => allPages.length - 1 === i }); refetchTotalTTYOutput(); trackEvent('refresh_clicked'); }, [refetch, refetchAlerts, refetchTotalTTYOutput, trackEvent]); const alerts = (0, _react.useMemo)(() => { let events = []; if (alertsData) { alertsData.pages.forEach(page => { events = events.concat(page.events); }); } return events; }, [alertsData]); const alertsCount = (0, _react.useMemo)(() => { var _alertsData$pages; return (alertsData === null || alertsData === void 0 ? void 0 : (_alertsData$pages = alertsData.pages) === null || _alertsData$pages === void 0 ? void 0 : _alertsData$pages[0].total) || 0; }, [alertsData]); const hasError = error || alertsError; const dataLoaded = data && ((_data$pages = data.pages) === null || _data$pages === void 0 ? void 0 : _data$pages.length) > (jumpToCursor ? 1 : 0); const renderIsLoading = isFetching && !dataLoaded; const hasData = dataLoaded && data.pages[0].events.length > 0; const { data: newUpdatedAlertsStatus } = (0, _hooks.useFetchAlertStatus)(updatedAlertsStatus, (_fetchAlertStatus$ = fetchAlertStatus[0]) !== null && _fetchAlertStatus$ !== void 0 ? _fetchAlertStatus$ : ''); (0, _react.useEffect)(() => { if (newUpdatedAlertsStatus) { setUpdatedAlertsStatus({ ...newUpdatedAlertsStatus }); // clearing alertUuids fetched without triggering a re-render fetchAlertStatus.shift(); } }, [newUpdatedAlertsStatus, fetchAlertStatus]); const onSearchIndexChange = (0, _react.useCallback)(i => { if (searchResults) { const process = searchResults[i]; if (process) { onProcessSelected(process); } } }, [onProcessSelected, searchResults]); (0, _react.useEffect)(() => { onSearchIndexChange(0); }, [onSearchIndexChange, searchResults]); const handleOnAlertDetailsClosed = (0, _react.useCallback)(alertUuid => { setFetchAlertStatus([alertUuid]); }, []); const toggleDetailPanel = (0, _react.useCallback)(() => { const newValue = !isDetailOpen; detailPanelCollapseFn.current(); setIsDetailOpen(newValue); if (newValue) { trackEvent('details_opened'); } else { trackEvent('details_closed'); } }, [isDetailOpen, trackEvent]); const onShowAlertDetails = (0, _react.useCallback)(alertUuid => { if (loadAlertDetails) { loadAlertDetails(alertUuid, () => handleOnAlertDetailsClosed(alertUuid)); trackEvent('alert_details_loaded'); } }, [loadAlertDetails, trackEvent, handleOnAlertDetailsClosed]); const handleOptionChange = (0, _react.useCallback)(checkedOptions => { setDisplayOptions(checkedOptions); if (checkedOptions.verboseMode !== (displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.verboseMode)) { if (checkedOptions.verboseMode) { trackEvent('verbose_mode_enabled'); } else { trackEvent('verbose_mode_disabled'); } } if (checkedOptions.timestamp !== (displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.timestamp)) { if (checkedOptions.timestamp) { trackEvent('timestamp_enabled'); } else { trackEvent('timestamp_disabled'); } } }, [displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.timestamp, displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.verboseMode, setDisplayOptions, trackEvent]); if (renderIsLoading) { return /*#__PURE__*/_react.default.createElement(_shared_imports.SectionLoading, null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.loadingProcessTree", defaultMessage: "Loading session\u2026" })); } if (!hasData) { return /*#__PURE__*/_react.default.createElement(_eui.EuiEmptyPrompt, { "data-test-subj": "sessionView:sessionViewProcessEventsEmpty", title: /*#__PURE__*/_react.default.createElement("h2", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.emptyDataTitle", defaultMessage: "No data to render" })), body: /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.emptyDataMessage", defaultMessage: "No process events found for this query." })) }); } return /*#__PURE__*/_react.default.createElement("div", { css: styles.sessionViewerComponent }, /*#__PURE__*/_react.default.createElement(_eui.EuiPanel, { hasShadow: false, borderRadius: "none", className: "sessionViewerToolbar" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { alignItems: "center", gutterSize: "s" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { "data-test-subj": "sessionView:sessionViewProcessEventsSearch" }, /*#__PURE__*/_react.default.createElement(_session_view_search_bar.SessionViewSearchBar, { searchQuery: searchQuery, totalMatches: (searchResults === null || searchResults === void 0 ? void 0 : searchResults.length) || 0, setSearchQuery: setSearchQuery, onPrevious: onSearchIndexChange, onNext: onSearchIndexChange, trackEvent: trackEvent })), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { title: /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, bytesOfOutput.value, " ", bytesOfOutput.unit, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.ttyToggleTip", defaultMessage: " of TTY output" })) }, /*#__PURE__*/_react.default.createElement(_eui.EuiButtonIcon, { isSelected: showTTY, display: showTTY ? 'fill' : 'empty', iconType: "apmTrace", onClick: onToggleTTY, size: "m", "aria-label": _translations.TOGGLE_TTY_PLAYER, "data-test-subj": "sessionView:TTYPlayerToggle", css: !hasTTYOutput && styles.fakeDisabled }))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiButtonIcon, { iconType: "refresh", display: "empty", onClick: handleRefresh, size: "m", "aria-label": _translations.REFRESH_SESSION, "data-test-subj": "sessionView:sessionViewRefreshButton", isLoading: isFetching })), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_session_view_display_options.SessionViewDisplayOptions, { displayOptions: displayOptions, onChange: handleOptionChange, showVerboseSearchTooltip: showVerboseSearchTooltip })), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { onClick: toggleDetailPanel, iconType: "list", "data-test-subj": "sessionView:sessionViewDetailPanelToggle", fill: !isDetailOpen }, _translations.DETAIL_PANEL)))), /*#__PURE__*/_react.default.createElement(_eui.EuiHorizontalRule, { margin: "none" }), /*#__PURE__*/_react.default.createElement(_eui.EuiResizableContainer, null, (EuiResizablePanel, EuiResizableButton, { togglePanel }) => { detailPanelCollapseFn.current = () => { togglePanel === null || togglePanel === void 0 ? void 0 : togglePanel('session-detail-panel', { direction: 'left' }); }; return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(EuiResizablePanel, { initialSize: 100, minSize: "60%", paddingSize: "none" }, hasError && /*#__PURE__*/_react.default.createElement(_eui.EuiEmptyPrompt, { iconType: "warning", color: "danger", title: /*#__PURE__*/_react.default.createElement("h2", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.errorHeading", defaultMessage: "Error loading Session View" })), body: /*#__PURE__*/_react.default.createElement("p", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.errorMessage", defaultMessage: "There was an error loading the Session View." })) }), hasData && /*#__PURE__*/_react.default.createElement("div", { css: styles.processTree }, /*#__PURE__*/_react.default.createElement(_process_tree.ProcessTree, { key: sessionEntityId + currentJumpToCursor, sessionEntityId: sessionEntityId, data: data.pages, searchQuery: searchQuery, selectedProcess: selectedProcess, onProcessSelected: onProcessSelected, onJumpToOutput: onJumpToOutput, jumpToEntityId: currentJumpToEntityId, investigatedAlertId: investigatedAlertId, isFetching: isFetching, hasPreviousPage: hasPreviousPage, hasNextPage: hasNextPage, fetchNextPage: fetchNextPage, fetchPreviousPage: fetchPreviousPage, setSearchResults: setSearchResults, updatedAlertsStatus: updatedAlertsStatus, onShowAlertDetails: onShowAlertDetails, showTimestamp: displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.timestamp, verboseMode: displayOptions === null || displayOptions === void 0 ? void 0 : displayOptions.verboseMode, trackEvent: trackEvent }))), /*#__PURE__*/_react.default.createElement(EuiResizableButton, { css: styles.resizeHandle }), /*#__PURE__*/_react.default.createElement(EuiResizablePanel, { id: "session-detail-panel", initialSize: 30, minSize: "320px", paddingSize: "none", css: styles.detailPanel }, /*#__PURE__*/_react.default.createElement(_session_view_detail_panel.SessionViewDetailPanel, { alerts: alerts, alertsCount: alertsCount, isFetchingAlerts: isFetchingAlerts, hasNextPageAlerts: hasNextPageAlerts, fetchNextPageAlerts: fetchNextPageAlerts, investigatedAlertId: investigatedAlertId, selectedProcess: selectedProcess, onJumpToEvent: onJumpToEvent, onShowAlertDetails: onShowAlertDetails }))); }), /*#__PURE__*/_react.default.createElement(_tty_player.TTYPlayer, { index: index, show: showTTY, sessionEntityId: sessionEntityId, sessionStartTime: sessionStartTime, onClose: onToggleTTY, isFullscreen: isFullScreen, onJumpToEvent: onJumpToEvent, autoSeekToEntityId: currentJumpToOutputEntityId, canReadPolicyManagement: canReadPolicyManagement, trackEvent: trackEvent })); }; // eslint-disable-next-line import/no-default-export exports.default = exports.SessionView = SessionView;