"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.EditAssigneesSelectable = void 0; var _react = _interopRequireWildcard(require("react")); var _lodash = require("lodash"); var _eui = require("@elastic/eui"); var _userProfileComponents = require("@kbn/user-profile-components"); var _use_bulk_get_user_profiles = require("../../../containers/user_profiles/use_bulk_get_user_profiles"); var _use_is_user_typing = require("../../../common/use_is_user_typing"); var _use_suggest_user_profiles = require("../../../containers/user_profiles/use_suggest_user_profiles"); var i18n = _interopRequireWildcard(require("./translations")); var _use_items_state = require("../use_items_state"); var _use_cases_context = require("../../cases_context/use_cases_context"); var _empty_message = require("../../user_profiles/empty_message"); var _no_matches = require("../../user_profiles/no_matches"); var _small_user_avatar = require("../../user_profiles/small_user_avatar"); var _no_selected_assignees = require("./no_selected_assignees"); 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 getUnknownUsers = (assignees, userProfiles) => { const unknownUsers = []; if (!userProfiles) { return unknownUsers; } for (const assignee of assignees) { if (!userProfiles.has(assignee)) { unknownUsers.push(assignee); } } return unknownUsers; }; const EditAssigneesSelectableComponent = ({ selectedCases, onChangeAssignees }) => { const { owner: owners } = (0, _use_cases_context.useCasesContext)(); const { euiTheme } = (0, _eui.useEuiTheme)(); const { isUserTyping, onContentChange, onDebounce } = (0, _use_is_user_typing.useIsUserTyping)(); const hasDataBeenSetToStateAfterFetched = (0, _react.useRef)(false); const assignees = (0, _react.useMemo)(() => new Set(selectedCases.map(theCase => theCase.assignees.map(({ uid }) => uid)).flat()), [selectedCases]); const { data, isLoading: isLoadingUserProfiles } = (0, _use_bulk_get_user_profiles.useBulkGetUserProfiles)({ uids: Array.from(assignees.values()) }); const userProfiles = (0, _react.useMemo)(() => data !== null && data !== void 0 ? data : new Map(), [data]); const unknownUsers = getUnknownUsers(assignees, userProfiles); const userProfileIds = [...userProfiles.keys(), ...unknownUsers]; const [searchValue, setSearchValue] = (0, _react.useState)(''); const { data: searchResultUserProfiles, isLoading: isLoadingSuggest } = (0, _use_suggest_user_profiles.useSuggestUserProfiles)({ name: searchValue, owners, onDebounce }); const itemToSelectableOption = (0, _react.useCallback)(item => { const userProfileFromData = item.data; const userProfile = (0, _lodash.isEmpty)(userProfileFromData) ? userProfiles.get(item.key) : userProfileFromData; if (isUserProfile(userProfile)) { return toSelectableOption(userProfile); } const profileInSuggestedUsers = searchResultUserProfiles === null || searchResultUserProfiles === void 0 ? void 0 : searchResultUserProfiles.find(profile => profile.uid === item.data.uid); if (profileInSuggestedUsers) { return toSelectableOption(profileInSuggestedUsers); } return { key: item.key, label: i18n.UNKNOWN, data: { unknownUser: true }, 'data-test-subj': `cases-actions-assignees-edit-selectable-assignee-${item.key}` }; }, [searchResultUserProfiles, userProfiles]); const { options, totalSelectedItems, onChange, onSelectNone, resetItems } = (0, _use_items_state.useItemsState)({ items: userProfileIds, selectedCases, fieldSelector: theCase => theCase.assignees.map(({ uid }) => uid), onChangeItems: onChangeAssignees, itemToSelectableOption }); if (data && !hasDataBeenSetToStateAfterFetched.current) { hasDataBeenSetToStateAfterFetched.current = true; resetItems(userProfileIds); } const finalOptions = getDisplayOptions({ searchResultUserProfiles: searchResultUserProfiles !== null && searchResultUserProfiles !== void 0 ? searchResultUserProfiles : [], options, searchValue, initialUserProfiles: userProfiles }); const isLoadingData = isLoadingUserProfiles || isLoadingSuggest || isUserTyping; const renderOption = (0, _react.useCallback)((option, search) => { var _option$itemIcon, _option$user, _option$user2; const icon = (_option$itemIcon = option.itemIcon) !== null && _option$itemIcon !== void 0 ? _option$itemIcon : 'empty'; const dataTestSubj = `cases-actions-assignees-edit-selectable-assignee-${option.key}-icon-${icon}`; const userInfo = option.user ? { user: option.user, data: option.data } : undefined; return /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, null, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { gutterSize: "s", alignItems: "center", justifyContent: "center", responsive: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiIcon, { type: icon, "data-test-subj": dataTestSubj })), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_small_user_avatar.SmallUserAvatar, { userInfo: userInfo })))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { alignItems: "center", justifyContent: "spaceBetween", gutterSize: "s", responsive: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, null, /*#__PURE__*/_react.default.createElement(_eui.EuiHighlight, { search: searchValue }, option.label)), (_option$user = option.user) !== null && _option$user !== void 0 && _option$user.email && ((_option$user2 = option.user) === null || _option$user2 === void 0 ? void 0 : _option$user2.email) !== option.label ? /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiTextColor, { color: option.disabled ? 'disabled' : 'subdued' }, searchValue ? /*#__PURE__*/_react.default.createElement(_eui.EuiHighlight, { search: searchValue }, option.user.email) : option.user.email)) : undefined)); }, [searchValue]); const onSearchChange = (0, _react.useCallback)(value => { setSearchValue(value); onContentChange(value); }, [onContentChange]); if (isLoadingUserProfiles) { return /*#__PURE__*/_react.default.createElement(_eui.EuiLoadingSpinner, null); } return /*#__PURE__*/_react.default.createElement(_eui.EuiSelectable, { options: finalOptions, searchable: true, searchProps: { placeholder: i18n.SEARCH_ASSIGNEES_PLACEHOLDER, isLoading: isLoadingData, isClearable: !isLoadingData, onChange: onSearchChange, value: searchValue, 'data-test-subj': 'cases-actions-assignees-edit-selectable-search-input' }, renderOption: renderOption, listProps: { showIcons: false }, onChange: onChange, noMatchesMessage: !isLoadingData ? /*#__PURE__*/_react.default.createElement(_no_matches.NoMatches, null) : /*#__PURE__*/_react.default.createElement(_empty_message.EmptyMessage, null), emptyMessage: /*#__PURE__*/_react.default.createElement(_no_selected_assignees.NoSelectedAssignees, { totalSelectedCases: selectedCases.length }), "data-test-subj": "cases-actions-assignees-edit-selectable", height: "full" }, (list, search) => { return /*#__PURE__*/_react.default.createElement(_react.default.Fragment, null, search, /*#__PURE__*/_react.default.createElement(_eui.EuiSpacer, { size: "s" }), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { alignItems: "center", justifyContent: "spaceBetween", responsive: false, direction: "row", css: { flexGrow: 0 }, gutterSize: "none" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false, css: { paddingLeft: euiTheme.size.s } }, /*#__PURE__*/_react.default.createElement(_eui.EuiText, { size: "xs", color: "subdued" }, i18n.SELECTED_ASSIGNEES(totalSelectedItems))), /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false, css: { marginLeft: 'auto' } }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexGroup, { responsive: false, direction: "row", alignItems: "center", justifyContent: "flexEnd", gutterSize: "xs" }, /*#__PURE__*/_react.default.createElement(_eui.EuiFlexItem, { grow: false }, /*#__PURE__*/_react.default.createElement(_eui.EuiButtonEmpty, { size: "xs", flush: "right", onClick: onSelectNone }, i18n.REMOVE_ASSIGNEES))))), /*#__PURE__*/_react.default.createElement(_eui.EuiHorizontalRule, { margin: "m" }), list); }); }; EditAssigneesSelectableComponent.displayName = 'EditAssigneesSelectable'; const EditAssigneesSelectable = /*#__PURE__*/_react.default.memo(EditAssigneesSelectableComponent); exports.EditAssigneesSelectable = EditAssigneesSelectable; const getDisplayOptions = ({ searchResultUserProfiles, options, searchValue, initialUserProfiles }) => { var _searchResultUserProf, _searchResultUserProf2; /** * If the user does not perform any search we do not want to show * the results of an empty search to the initial list of users. * We also filter out users that appears both in the initial list * and the search results */ const searchResultsOptions = (0, _lodash.isEmpty)(searchValue) ? [] : (_searchResultUserProf = searchResultUserProfiles === null || searchResultUserProfiles === void 0 ? void 0 : (_searchResultUserProf2 = searchResultUserProfiles.filter(profile => !options.find(option => isMatchingOption(option, profile)))) === null || _searchResultUserProf2 === void 0 ? void 0 : _searchResultUserProf2.map(profile => toSelectableOption(profile))) !== null && _searchResultUserProf !== void 0 ? _searchResultUserProf : []; /** * In the initial view, when the user does not perform any search, * we want to filter out options that are not in the initial user profile * mapping or profiles returned by the search result that are not selected. * We want to keep unknown users as they can only be available from the * selected cases and not from search results */ const filteredOptions = (0, _lodash.isEmpty)(searchValue) ? options.filter(option => { var _option$data, _option$data2, _option$data3; return initialUserProfiles.has(option === null || option === void 0 ? void 0 : (_option$data = option.data) === null || _option$data === void 0 ? void 0 : _option$data.uid) || (option === null || option === void 0 ? void 0 : (_option$data2 = option.data) === null || _option$data2 === void 0 ? void 0 : _option$data2.itemIcon) !== 'empty' || ((_option$data3 = option.data) === null || _option$data3 === void 0 ? void 0 : _option$data3.unknownUser); }) : [...options]; const finalOptions = sortOptionsAlphabetically([...searchResultsOptions, ...filteredOptions]); return finalOptions; }; const sortOptionsAlphabetically = options => /** * sortBy will not mutate the original array. * It will return a new sorted array * */ (0, _lodash.sortBy)(options, option => option.label); const toSelectableOption = userProfile => { return { key: userProfile.uid, label: (0, _userProfileComponents.getUserDisplayName)(userProfile.user), data: userProfile, 'data-test-subj': `cases-actions-assignees-edit-selectable-assignee-${userProfile.uid}` }; }; const isMatchingOption = (option, profile) => { return option.key === profile.uid; }; const isUserProfile = userProfile => !!userProfile && !!userProfile.uid && !!userProfile.user;