"use strict"; var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault"); Object.defineProperty(exports, "__esModule", { value: true }); exports.AgentsTable = void 0; var _fp = require("lodash/fp"); var _react = _interopRequireWildcard(require("react")); var _eui = require("@elastic/eui"); var _fastDeepEqual = _interopRequireDefault(require("fast-deep-equal")); var _useDebounce = _interopRequireDefault(require("react-use/lib/useDebounce")); var _i18nReact = require("@kbn/i18n-react"); var _kibana = require("../common/lib/kibana"); var _use_all_agents = require("./use_all_agents"); var _use_agent_groups = require("./use_agent_groups"); var _agent_grouper = require("./agent_grouper"); var _helpers = require("./helpers"); var _translations = require("./translations"); var _types = require("./types"); 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. */ const perPage = 10; const DEBOUNCE_DELAY = 300; // ms const AgentsTableComponent = ({ agentSelection, onChange, error }) => { const { docLinks } = (0, _kibana.useKibana)().services; // search related const [searchValue, setSearchValue] = (0, _react.useState)(''); const [modifyingSearch, setModifyingSearch] = (0, _react.useState)(false); const [debouncedSearchValue, setDebouncedSearchValue] = (0, _react.useState)(''); (0, _useDebounce.default)(() => { // update the real search value, set the typing flag setDebouncedSearchValue(searchValue); setModifyingSearch(false); }, DEBOUNCE_DELAY, [searchValue]); // grouping related const { isLoading: groupsLoading, data: agentGroupsData, isFetched: groupsFetched } = (0, _use_agent_groups.useAgentGroups)(); const { isLoading: agentsLoading, data: agents, isFetched: agentsFetched } = (0, _use_all_agents.useAllAgents)(debouncedSearchValue, { perPage }); // option related const [options, setOptions] = (0, _react.useState)([]); const [selectedOptions, setSelectedOptions] = (0, _react.useState)([]); const [numAgentsSelected, setNumAgentsSelected] = (0, _react.useState)(0); const defaultValueInitialized = (0, _react.useRef)(false); const onSelection = (0, _react.useCallback)(selection => { // TODO?: optimize this by making the selection computation incremental const { newAgentSelection, selectedAgents, selectedGroups } = (0, _helpers.generateAgentSelection)(selection); if (newAgentSelection.allAgentsSelected) { var _agentGroupsData$tota; setNumAgentsSelected((_agentGroupsData$tota = agentGroupsData === null || agentGroupsData === void 0 ? void 0 : agentGroupsData.total) !== null && _agentGroupsData$tota !== void 0 ? _agentGroupsData$tota : 0); } else { var _agentGroupsData$grou, _agentGroupsData$grou2; const checkAgent = (0, _helpers.generateAgentCheck)(selectedGroups); setNumAgentsSelected( // filter out all the agents counted by selected policies and platforms selectedAgents.filter(checkAgent).length + // add the number of agents added via policy and platform groups (0, _helpers.getNumAgentsInGrouping)(selectedGroups) - // subtract the number of agents double counted by policy/platform selections (0, _helpers.getNumOverlapped)(selectedGroups, (_agentGroupsData$grou = agentGroupsData === null || agentGroupsData === void 0 ? void 0 : (_agentGroupsData$grou2 = agentGroupsData.groups) === null || _agentGroupsData$grou2 === void 0 ? void 0 : _agentGroupsData$grou2.overlap) !== null && _agentGroupsData$grou !== void 0 ? _agentGroupsData$grou : {})); } onChange(newAgentSelection); setSelectedOptions(selection); }, [agentGroupsData, onChange]); (0, _react.useEffect)(() => { const handleSelectedOptions = (selection, label) => { const agentOptions = (0, _fp.find)(['label', label], options); if (agentOptions) { var _agentOptions$options; const defaultOptions = (_agentOptions$options = agentOptions.options) === null || _agentOptions$options === void 0 ? void 0 : _agentOptions$options.filter(option => { if (option.key) { return selection.includes(option.key); } }); if (defaultOptions !== null && defaultOptions !== void 0 && defaultOptions.length) { onSelection(defaultOptions); defaultValueInitialized.current = true; } } }; if (agentSelection && !defaultValueInitialized.current && options.length) { var _agentSelection$polic, _agentSelection$agent; if (agentSelection.allAgentsSelected) { const allAgentsOptions = (0, _fp.find)(['label', _translations.ALL_AGENTS_LABEL], options); if (allAgentsOptions !== null && allAgentsOptions !== void 0 && allAgentsOptions.options) { onSelection(allAgentsOptions.options); defaultValueInitialized.current = true; } } if ((_agentSelection$polic = agentSelection.policiesSelected) !== null && _agentSelection$polic !== void 0 && _agentSelection$polic.length) { handleSelectedOptions(agentSelection.policiesSelected, _translations.AGENT_POLICY_LABEL); } if ((_agentSelection$agent = agentSelection.agents) !== null && _agentSelection$agent !== void 0 && _agentSelection$agent.length) { handleSelectedOptions(agentSelection.agents, _translations.AGENT_SELECTION_LABEL); } } }, [agentSelection, onSelection, options, selectedOptions]); (0, _react.useEffect)(() => { if (agentsFetched && groupsFetched && agentGroupsData) { // Cap policies to 10 on init dropdown const policies = ((agentGroupsData === null || agentGroupsData === void 0 ? void 0 : agentGroupsData.groups.policies) || []).slice(0, searchValue === '' ? 10 : undefined); const grouper = new _agent_grouper.AgentGrouper(); // update the groups when groups or agents have changed grouper.setTotalAgents(agentGroupsData === null || agentGroupsData === void 0 ? void 0 : agentGroupsData.total); grouper.updateGroup(_types.AGENT_GROUP_KEY.Platform, agentGroupsData === null || agentGroupsData === void 0 ? void 0 : agentGroupsData.groups.platforms); grouper.updateGroup(_types.AGENT_GROUP_KEY.Policy, policies); // @ts-expect-error update types grouper.updateGroup(_types.AGENT_GROUP_KEY.Agent, agents); const newOptions = grouper.generateOptions(); setOptions(prevOptions => !(0, _fastDeepEqual.default)(prevOptions, newOptions) ? newOptions : prevOptions); } }, [groupsLoading, agents, agentsFetched, groupsFetched, agentGroupsData, searchValue]); const renderOption = (0, _react.useCallback)((option, searchVal, contentClassName) => { var _value$size; const { label, value } = option; return (value === null || value === void 0 ? void 0 : value.groupType) === _types.AGENT_GROUP_KEY.Agent ? /*#__PURE__*/_react.default.createElement(_eui.EuiHealth, { color: (value === null || value === void 0 ? void 0 : value.status) === 'online' ? 'success' : 'danger' }, /*#__PURE__*/_react.default.createElement("span", { className: contentClassName }, /*#__PURE__*/_react.default.createElement(_eui.EuiHighlight, { search: searchVal }, label))) : /*#__PURE__*/_react.default.createElement("span", { className: contentClassName }, /*#__PURE__*/_react.default.createElement("span", null, "[", (_value$size = value === null || value === void 0 ? void 0 : value.size) !== null && _value$size !== void 0 ? _value$size : 0, "]"), "\xA0", /*#__PURE__*/_react.default.createElement(_eui.EuiHighlight, { search: searchVal }, label)); }, []); const onSearchChange = (0, _react.useCallback)(v => { // set the typing flag and update the search value setModifyingSearch(v !== ''); setSearchValue(v); }, []); const isFetched = groupsFetched && agentsFetched && agentGroupsData; const renderNoAgentAvailableWarning = () => { if (isFetched && !options.length) { return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, /*#__PURE__*/_react.default.createElement(_eui.EuiCallOut, { color: "danger", size: "s", iconType: "warning", title: _translations.NO_AGENT_AVAILABLE_TITLE }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.osquery.agents.noAgentAvailableDescription", defaultMessage: "Before you can query agents, they must be enrolled in an agent policy with the Osquery integration installed. Refer to {docsLink} for more information." // eslint-disable-next-line react-perf/jsx-no-new-object-as-prop , values: { docsLink: /*#__PURE__*/_react.default.createElement(_eui.EuiLink, { href: `${docLinks.links.fleet.agentPolicy}#apply-a-policy`, target: '_blank' }, /*#__PURE__*/_react.default.createElement(_i18nReact.FormattedMessage, { id: "xpack.osquery.agents.noAgentAvailableDescription.docsLink", defaultMessage: "Apply a policy" })) } })), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "s" })); } return null; }; return /*#__PURE__*/_react.default.createElement("div", null, /*#__PURE__*/_react.default.createElement(_eui.EuiFormRow, { label: _translations.AGENT_SELECTION_LABEL, fullWidth: true, isInvalid: !!error, error: error }, /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, renderNoAgentAvailableWarning(), /*#__PURE__*/_react.default.createElement(_eui.EuiComboBox, { "data-test-subj": "agentSelection", placeholder: _translations.SELECT_AGENT_LABEL, isLoading: groupsLoading || agentsLoading || modifyingSearch, options: options, isClearable: true, fullWidth: true, onSearchChange: onSearchChange, selectedOptions: selectedOptions, onChange: onSelection, renderOption: renderOption }))), /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "xs" }), numAgentsSelected > 0 ? /*#__PURE__*/_react.default.createElement("span", null, (0, _translations.generateSelectedAgentsMessage)(numAgentsSelected)) : ''); }; AgentsTableComponent.displayName = 'AgentsTable'; const AgentsTable = /*#__PURE__*/_react.default.memo(AgentsTableComponent, _fastDeepEqual.default); exports.AgentsTable = AgentsTable;