packages/lib/reporting-components/sharing-setting/sharing-setting.js (125 lines of code) (raw):

import React, {useCallback, useMemo, useState, useEffect} from 'react'; import PropTypes from 'prop-types'; import Select from '@jetbrains/ring-ui/components/select/select'; import {i18n} from 'hub-dashboard-addons/dist/localization'; import Anchor from '@jetbrains/ring-ui/components/dropdown/anchor'; import BackendTypes from '../backend-types/backend-types'; import { makeDropdownOptions, userGroupToSelectOption, hideUsersFromList } from './make-dropdown-options'; function formatSelectedOptionsText( selectedUsersOrGroups, implicitSelectedUsers = [] ) { if (!selectedUsersOrGroups.length) { return implicitSelectedUsers.length ? `${i18n('Owner')} (${makeLabelFromArray(implicitSelectedUsers)})` : i18n('Owner'); } const allUsersGroup = (selectedUsersOrGroups || []). filter(group => group.allUsersGroup)[0]; if (allUsersGroup) { return allUsersGroup.name; } return makeLabelFromArray([ ...hideUsersFromList(selectedUsersOrGroups, implicitSelectedUsers), ...implicitSelectedUsers] ); function makeLabelFromArray(usersOrGroups) { const names = usersOrGroups. filter((s, i, arr) => arr.findIndex(it => it.id === s.id) === i). map(s => s.name); if (names.length === 1) { return names[0]; } const namesToDisplay = 2; const othersNum = names.length - namesToDisplay; const others = othersNum > 0 ? ` +${othersNum}` : ''; return `${names[0]}, ${names[1]}${others}`; } } function settingValueToSelectedArray(sharingSettingValue) { return [ ...(sharingSettingValue.permittedUsers || []), ...(sharingSettingValue.permittedGroups || []) ]; } const SharingSetting = ( {value, implicitSelected, getOptions, onChange, disabled} ) => { const [loading, setLoading] = useState(true); const [options, setOptions] = useState(null); const [selected, setSelected] = useState(settingValueToSelectedArray(value)); useEffect(() => { setSelected(settingValueToSelectedArray(value)); }, [value]); const getAllOptions = useCallback(() => [ ...selected, ...(options && options.bestGroups || []), ...(options && options.groups || []), ...(options && options.users || []) ], [selected, options]); const loadValues = useCallback(async (query = '') => { setLoading(true); setOptions(await getOptions(query)); setLoading(false); }, [getOptions]); const onChangeValue = useCallback(selectedOptions => { const valuableOptions = selectedOptions. map(selectedOption => getAllOptions(). find(o => o.id === selectedOption.key)). filter(v => !!v); onChange({ id: value.id, $type: value.$type, projectBased: value.projectBased || false, permittedUsers: (valuableOptions || []). filter(option => option.$type === BackendTypes.get().User), permittedGroups: (valuableOptions || []). filter(option => option.$type === BackendTypes.get().UserGroup) }); }, [getAllOptions, onChange, value]); const dropdownOptions = useMemo(() => ( options ? makeDropdownOptions(options) : [] ), [options]); const hoverTitle = [...selected, ...(implicitSelected || [])]. map(it => it.name).join(', '); const anchor = useCallback(({wrapperProps, buttonProps, popup}) => ( <span {...wrapperProps} title={hoverTitle} > <Anchor {...buttonProps} data-test="ring-select__focus" disabled={disabled} > { formatSelectedOptionsText(selected, implicitSelected) } </Anchor> {popup} </span> ), [selected, implicitSelected]); // eslint-disable-next-line @typescript-eslint/no-explicit-any const passthruFilter = s => s; const selectedTagsOptions = (selected || []).map(userGroupToSelectOption); return ( <Select type={Select.Type.CUSTOM} filter={{ fn: passthruFilter, placeholder: i18n('Filter users, groups, and teams') }} multiple={true} data={dropdownOptions} customAnchor={anchor} loading={loading} popupClassName="sharing-setting__popup" selected={selectedTagsOptions} onFilter={loadValues} disabled={disabled} onBeforeOpen={loadValues} tags={{ reset: { separator: false, label: i18n('Reset to default (owner)') } }} onChange={onChangeValue} /> ); }; SharingSetting.propTypes = { value: PropTypes.object.isRequired, implicitSelected: PropTypes.array, getOptions: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired, disabled: PropTypes.bool }; export default SharingSetting;