"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EXEC_USER_CHANGE = exports.COLLAPSE_ALL = void 0; exports.ProcessTreeNode = ProcessTreeNode; var _react = _interopRequireWildcard(require("react")); var _eui = require("@elastic/eui"); var _i18n = require("@kbn/i18n"); var _i18nReact = require("@kbn/i18n-react"); var _lodash = require("lodash"); var _data_or_dash = require("../../utils/data_or_dash"); var _use_visible = require("../../hooks/use_visible"); var _process_tree_alerts = require("../process_tree_alerts"); var _buttons = require("./buttons"); var _use_button_styles = require("./use_button_styles"); var _styles = require("./styles"); var _split_text = require("./split_text"); var _nbsp = require("./nbsp"); var _hooks = require("../../hooks"); var _text_highlight = require("./text_highlight"); 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. */ /* * 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 EXEC_USER_CHANGE = _i18n.i18n.translate('xpack.sessionView.execUserChange', { defaultMessage: 'Exec user change' }); exports.EXEC_USER_CHANGE = EXEC_USER_CHANGE; const COLLAPSE_ALL = _i18n.i18n.translate('xpack.sessionView.collapseAll', { defaultMessage: 'Collapse all' }); exports.COLLAPSE_ALL = COLLAPSE_ALL; /** * Renders a node on the process tree */ function ProcessTreeNode({ process, isSessionLeader = false, depth = 0, onProcessSelected, jumpToEntityId, investigatedAlertId, selectedProcess, showTimestamp, verboseMode, searchResults, scrollerRef, onChangeJumpToEventVisibility, onShowAlertDetails, onJumpToOutput, loadPreviousButton, loadNextButton, handleCollapseProcessTree, trackEvent }) { var _processDetails$proce2, _processDetails$proce3, _parent$user; const [childrenExpanded, setChildrenExpanded] = (0, _react.useState)(isSessionLeader || process.autoExpand); const [alertsExpanded, setAlertsExpanded] = (0, _react.useState)(false); const { searchMatched } = process; const dateFormat = (0, _hooks.useDateFormat)(); (0, _react.useEffect)(() => { setChildrenExpanded(process.autoExpand); }, [process.autoExpand]); // forces nodes to expand if the selected process is a descendant (0, _react.useEffect)(() => { if (!childrenExpanded && selectedProcess) { if (selectedProcess.isDescendantOf(process)) { setChildrenExpanded(true); } } }, [selectedProcess, process, childrenExpanded]); const alerts = process.getAlerts(); const hasAlerts = !!alerts.length; const hasOutputs = process.hasOutput(); const hasInvestigatedAlert = (0, _react.useMemo)(() => !!(hasAlerts && alerts.find(alert => { var _alert$kibana, _alert$kibana$alert; return investigatedAlertId && investigatedAlertId === ((_alert$kibana = alert.kibana) === null || _alert$kibana === void 0 ? void 0 : (_alert$kibana$alert = _alert$kibana.alert) === null || _alert$kibana$alert === void 0 ? void 0 : _alert$kibana$alert.uuid); })), [hasAlerts, alerts, investigatedAlertId]); const isSelected = (selectedProcess === null || selectedProcess === void 0 ? void 0 : selectedProcess.id) === process.id; const styles = (0, _styles.useStyles)({ depth, hasAlerts, hasInvestigatedAlert, isSelected, isSessionLeader }); const buttonStyles = (0, _use_button_styles.useButtonStyles)(); const nodeRef = (0, _use_visible.useVisible)({ viewPortEl: scrollerRef.current, visibleCallback: (0, _react.useCallback)((isVisible, isAbove) => { onChangeJumpToEventVisibility(isVisible, isAbove); }, [onChangeJumpToEventVisibility]), shouldAddListener: hasInvestigatedAlert }); const alertTypeCounts = (0, _react.useMemo)(() => { const alertCounts = (0, _lodash.chain)(alerts).groupBy(alert => { var _alert$event; const category = (_alert$event = alert.event) === null || _alert$event === void 0 ? void 0 : _alert$event.category; if (Array.isArray(category)) { return category === null || category === void 0 ? void 0 : category[0]; } return category; }).map((processAlerts, alertCategory) => ({ category: alertCategory, count: processAlerts.length })).value(); return alertCounts; }, [alerts]); (0, _react.useEffect)(() => { var _nodeRef$current; if (process.id === (selectedProcess === null || selectedProcess === void 0 ? void 0 : selectedProcess.id) && (_nodeRef$current = nodeRef.current) !== null && _nodeRef$current !== void 0 && _nodeRef$current.scrollIntoView) { nodeRef.current.scrollIntoView({ behavior: 'smooth', block: 'nearest' }); } }, [selectedProcess, process, nodeRef]); // Automatically expand alerts list when investigating an alert (0, _react.useEffect)(() => { if (hasInvestigatedAlert) { setAlertsExpanded(true); } }, [hasInvestigatedAlert]); const onChildrenToggle = (0, _react.useCallback)(() => { const newValue = !childrenExpanded; setChildrenExpanded(newValue); trackEvent(newValue ? 'children_opened' : 'children_closed'); }, [childrenExpanded, trackEvent]); const onAlertsToggle = (0, _react.useCallback)(() => { const newValue = !alertsExpanded; setAlertsExpanded(newValue); trackEvent(newValue ? 'alerts_opened' : 'alerts_closed'); }, [alertsExpanded, trackEvent]); const onProcessClicked = (0, _react.useCallback)(e => { e.stopPropagation(); const selection = window.getSelection(); // do not select the command if the user was just selecting text for copy. if (selection && selection.type === 'Range') { return; } onProcessSelected === null || onProcessSelected === void 0 ? void 0 : onProcessSelected(process); if (isSessionLeader && scrollerRef.current) { scrollerRef.current.scrollTop = 0; } trackEvent('process_selected'); }, [isSessionLeader, onProcessSelected, process, scrollerRef, trackEvent]); const processDetails = process.getDetails(); const hasExec = process.hasExec(); const onOutputClicked = (0, _react.useCallback)(() => { var _processDetails$proce; const entityId = (_processDetails$proce = processDetails.process) === null || _processDetails$proce === void 0 ? void 0 : _processDetails$proce.entity_id; if (entityId) { onJumpToOutput(entityId); } trackEvent('output_clicked'); }, [onJumpToOutput, (_processDetails$proce2 = processDetails.process) === null || _processDetails$proce2 === void 0 ? void 0 : _processDetails$proce2.entity_id, trackEvent]); const processIcon = (0, _react.useMemo)(() => { if (!process.parent) { return 'unlink'; } else if (hasExec) { return 'console'; } else { return 'branch'; } }, [hasExec, process.parent]); const iconTooltip = (0, _react.useMemo)(() => { if (!process.parent) { return _i18n.i18n.translate('xpack.sessionView.processNode.tooltipOrphan', { defaultMessage: 'Process missing parent (orphan)' }); } else if (hasExec) { return _i18n.i18n.translate('xpack.sessionView.processNode.tooltipExec', { defaultMessage: "Process exec'd" }); } else { return _i18n.i18n.translate('xpack.sessionView.processNode.tooltipFork', { defaultMessage: 'Process forked (no exec)' }); } }, [hasExec, process.parent]); const children = process.getChildren(verboseMode); const user = processDetails === null || processDetails === void 0 ? void 0 : (_processDetails$proce3 = processDetails.process) === null || _processDetails$proce3 === void 0 ? void 0 : _processDetails$proce3.user; const userName = (0, _react.useMemo)(() => { if (user !== null && user !== void 0 && user.name) { return user.name; } else if ((user === null || user === void 0 ? void 0 : user.id) === '0') { return 'root'; } else if (user !== null && user !== void 0 && user.id) { return `uid: ${user === null || user === void 0 ? void 0 : user.id}`; } return '-'; }, [user === null || user === void 0 ? void 0 : user.id, user === null || user === void 0 ? void 0 : user.name]); if (!(processDetails !== null && processDetails !== void 0 && processDetails.process)) { return null; } const id = process.id; const { args, name, tty, parent, working_directory: workingDirectory, start } = processDetails.process; const shouldRenderChildren = isSessionLeader || childrenExpanded && (children === null || children === void 0 ? void 0 : children.length) > 0; const childrenTreeDepth = depth + 1; const showUserEscalation = !isSessionLeader && !!(user !== null && user !== void 0 && user.id) && user.id !== (parent === null || parent === void 0 ? void 0 : (_parent$user = parent.user) === null || _parent$user === void 0 ? void 0 : _parent$user.id); const interactiveSession = !!tty; const sessionIcon = interactiveSession ? 'desktop' : 'gear'; const iconTestSubj = hasExec ? 'sessionView:processTreeNodeExecIcon' : 'sessionView:processTreeNodeForkIcon'; const timeStampsNormal = (0, _eui.formatDate)(start, dateFormat); const promptText = `${workingDirectory !== null && workingDirectory !== void 0 ? workingDirectory : ''} ${args === null || args === void 0 ? void 0 : args.join(' ')}`; return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement("div", { "data-id": id, key: id + searchMatched, css: styles.processNode, "data-test-subj": "sessionView:processTreeNode", ref: nodeRef }, /*#__PURE__*/_react.default.createElement("div", { "data-test-subj": "sessionView:processTreeNodeRow", css: styles.wrapper, onClick: onProcessClicked }, isSessionLeader ? /*#__PURE__*/_react.default.createElement("span", { css: styles.sessionLeader }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, { type: sessionIcon, css: styles.icon }), /*#__PURE__*/_react.default.createElement(_nbsp.Nbsp, null), /*#__PURE__*/_react.default.createElement("b", { css: styles.darkText }, (0, _data_or_dash.dataOrDash)(name || (args === null || args === void 0 ? void 0 : args[0]))), /*#__PURE__*/_react.default.createElement(_nbsp.Nbsp, null), /*#__PURE__*/_react.default.createElement("span", null, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.sessionView.startedBy", defaultMessage: "started by" })), /*#__PURE__*/_react.default.createElement(_nbsp.Nbsp, null), /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, { type: "user" }), /*#__PURE__*/_react.default.createElement(_nbsp.Nbsp, null), /*#__PURE__*/_react.default.createElement("b", { css: styles.darkText }, userName), /*#__PURE__*/_react.default.createElement(_nbsp.Nbsp, null), /*#__PURE__*/_react.default.createElement("span", { css: styles.jumpToTop }, /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { title: COLLAPSE_ALL }, /*#__PURE__*/_react.default.createElement(_eui.EuiButtonIcon, { size: "xs", iconType: "fold", onClick: handleCollapseProcessTree })))) : /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, showTimestamp && /*#__PURE__*/_react.default.createElement("span", { "data-test-subj": "sessionView:processTreeNodeTimestamp", css: styles.timeStamp }, timeStampsNormal), /*#__PURE__*/_react.default.createElement(_eui.EuiToolTip, { position: "top", content: iconTooltip }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, { "data-test-subj": iconTestSubj, type: processIcon, css: styles.icon })), /*#__PURE__*/_react.default.createElement("span", { css: styles.textSection }, /*#__PURE__*/_react.default.createElement(_text_highlight.TextHighlight, { text: promptText, match: process.searchMatched, highlightStyle: styles.searchHighlight }, /*#__PURE__*/_react.default.createElement(_split_text.SplitText, { css: styles.workingDir }, (0, _data_or_dash.dataOrDash)(workingDirectory) + ' '), /*#__PURE__*/_react.default.createElement(_split_text.SplitText, { css: styles.darkText }, `${(0, _data_or_dash.dataOrDash)(args === null || args === void 0 ? void 0 : args[0])}`), /*#__PURE__*/_react.default.createElement(_split_text.SplitText, null, args && args.length > 1 ? ' ' + (args === null || args === void 0 ? void 0 : args.slice(1).join(' ')) : '')))), showUserEscalation && /*#__PURE__*/_react.default.createElement(_eui.EuiButton, { "data-test-subj": "sessionView:processTreeNodeRootEscalationFlag", css: buttonStyles.userChangedButton, "aria-label": EXEC_USER_CHANGE }, EXEC_USER_CHANGE, " (", userName, ")"), !isSessionLeader && children.length > 0 && /*#__PURE__*/_react.default.createElement(_buttons.ChildrenProcessesButton, { isExpanded: childrenExpanded, onToggle: onChildrenToggle }), hasAlerts && /*#__PURE__*/_react.default.createElement(_buttons.AlertButton, { onToggle: onAlertsToggle, alertTypeCounts: alertTypeCounts, isExpanded: alertsExpanded, alertsCount: alerts.length }), hasOutputs && /*#__PURE__*/_react.default.createElement(_buttons.OutputButton, { onClick: onOutputClicked }))), alertsExpanded && /*#__PURE__*/_react.default.createElement(_process_tree_alerts.ProcessTreeAlerts, { alerts: alerts, alertTypeCounts: alertTypeCounts, investigatedAlertId: investigatedAlertId, isProcessSelected: isSelected, onAlertSelected: onProcessClicked, onShowAlertDetails: onShowAlertDetails }), shouldRenderChildren && /*#__PURE__*/_react.default.createElement("div", { css: styles.children }, loadPreviousButton, children.map(child => { return /*#__PURE__*/_react.default.createElement(ProcessTreeNode, { key: child.id, process: child, depth: childrenTreeDepth, onProcessSelected: onProcessSelected, onJumpToOutput: onJumpToOutput, jumpToEntityId: jumpToEntityId, investigatedAlertId: investigatedAlertId, selectedProcess: selectedProcess, showTimestamp: showTimestamp, verboseMode: verboseMode, searchResults: searchResults, scrollerRef: scrollerRef, onChangeJumpToEventVisibility: onChangeJumpToEventVisibility, onShowAlertDetails: onShowAlertDetails, trackEvent: trackEvent }); }), loadNextButton)); }