import React, { useState, useEffect, useCallback } from 'react'; import useDeepCompareEffect from 'use-deep-compare-effect'; import PropTypes from 'prop-types'; import { shallowEqual, useSelector, useDispatch } from 'react-redux'; import { TableVariant } from '@patternfly/react-table'; import { Tabs, Tab, TabTitleText, Split, SplitItem, Button, Select, SelectVariant, SelectOption, Dropdown, DropdownItem, KebabToggle, } from '@patternfly/react-core'; import { STATUS } from 'foremanReact/constants'; import { translate as __ } from 'foremanReact/common/I18n'; import onSelect from '../../../../components/Table/helpers'; import TableWrapper from '../../../../components/Table/TableWrapper'; import { selectCVFilterPackageGroups, selectCVFilterPackageGroupStatus, selectCVFilterPackageGroupError, selectCVFilters, selectCVFilterDetails, } from '../ContentViewDetailSelectors'; import AddedStatusLabel from '../../../../components/AddedStatusLabel'; import getContentViewDetails, { addCVFilterRule, removeCVFilterRule, getCVFilterPackageGroups, deleteContentViewFilterRules, addContentViewFilterRules, } from '../ContentViewDetailActions'; import AffectedRepositoryTable from './AffectedRepositories/AffectedRepositoryTable'; import { ADDED, ALL_STATUSES, NOT_ADDED } from '../../ContentViewsConstants'; import { hasPermission } from '../../helpers'; const CVPackageGroupFilterContent = ({ cvId, filterId, showAffectedRepos, setShowAffectedRepos, details, }) => { const dispatch = useDispatch(); const { results: filterResults } = useSelector(state => selectCVFilters(state, cvId), shallowEqual); const response = useSelector(state => selectCVFilterPackageGroups(state, cvId, filterId), shallowEqual); const status = useSelector(state => selectCVFilterPackageGroupStatus(state, cvId, filterId), shallowEqual); const error = useSelector(state => selectCVFilterPackageGroupError(state, cvId, filterId), shallowEqual); const filterDetails = useSelector(state => selectCVFilterDetails(state, cvId, filterId), shallowEqual); const { repositories = [] } = filterDetails; const [rows, setRows] = useState([]); const [searchQuery, updateSearchQuery] = useState(''); const [activeTabKey, setActiveTabKey] = useState(0); const loading = status === STATUS.PENDING; const [bulkActionOpen, setBulkActionOpen] = useState(false); const [selectOpen, setSelectOpen] = useState(false); const [selectedIndex, setSelectedIndex] = useState(0); const deselectAll = () => setRows(rows.map(row => ({ ...row, selected: false }))); const toggleBulkAction = () => setBulkActionOpen(prevState => !prevState); const hasAddedSelected = rows.some(({ selected, added }) => selected && added); const hasNotAddedSelected = rows.some(({ selected, added }) => selected && !added); const { results, ...metadata } = response; const { permissions } = details; const columnHeaders = [ __('Name'), __('Product'), __('Repository'), __('Description'), __('Status'), ]; const allAddedNotAdded = [ ALL_STATUSES, ADDED, NOT_ADDED, ]; const selectedAdded = allAddedNotAdded[selectedIndex]; const fetchItems = useCallback((params) => { const adjustedParams = { ...params }; switch (selectedIndex) { case 0: adjustedParams.show_all_for = 'content_view_filter'; adjustedParams.available_for = undefined; break; case 1: adjustedParams.show_all_for = undefined; adjustedParams.available_for = undefined; break; case 2: adjustedParams.show_all_for = undefined; adjustedParams.available_for = 'content_view_filter'; break; default: } return getCVFilterPackageGroups(cvId, filterId, adjustedParams); }, [cvId, filterId, selectedIndex]); const buildRows = useCallback(() => { const newRows = []; const filterRules = filterResults.find(({ id }) => id === Number(filterId))?.rules || []; results.forEach((packageGroups) => { const { name, description, repository: { name: repositoryName, product: { name: productName }, }, filter_ids: filterIds, ...rest } = packageGroups; const cells = [ { title: name }, { title: productName }, { title: repositoryName }, { title: description }, { title: }, ]; newRows.push({ cells, packagefilterId: filterRules?.find(({ uuid }) => uuid === rest.uuid)?.id, added: filterIds.includes(parseInt(filterId, 10)), ...rest, name, }); }); return newRows.sort(({ added: addedA }, { added: addedB }) => { if (addedA === addedB) return 0; return addedA ? -1 : 1; }); }, [filterResults, filterId, results]); const bulkAdd = () => { setBulkActionOpen(false); const addData = rows.filter(({ selected, added }) => selected && !added).map(({ uuid }) => ({ uuid })); dispatch(addContentViewFilterRules(filterId, addData, () => dispatch(getContentViewDetails(cvId)))); deselectAll(); }; const bulkRemove = () => { setBulkActionOpen(false); const packageFilterIds = rows.filter(({ selected, added }) => selected && added).map(({ packagefilterId }) => packagefilterId); dispatch(deleteContentViewFilterRules(filterId, packageFilterIds, () => dispatch(getContentViewDetails(cvId)))); deselectAll(); }; useEffect(() => { if (!repositories.length && showAffectedRepos) { setActiveTabKey(1); } else { setActiveTabKey(0); } }, [showAffectedRepos, repositories.length]); useDeepCompareEffect(() => { if (!loading && results) { const newRows = buildRows(); setRows(newRows); } }, [response, loading, buildRows, results]); const actionResolver = ({ added }) => [ { title: __('Add'), isDisabled: added, onClick: (_event, _rowId, { uuid }) => { dispatch(addCVFilterRule(filterId, { uuid }, () => dispatch(getContentViewDetails(cvId)))); }, }, { title: __('Remove'), isDisabled: !added, onClick: (_event, _rowId, { packagefilterId }) => { dispatch(removeCVFilterRule(filterId, packagefilterId, () => dispatch(getContentViewDetails(cvId)))); }, }, ]; const emptyContentTitle = __('No package groups yet'); const emptyContentBody = __('Add repositories with package groups to content view to select them here.'); const emptySearchTitle = __('No matching filter rules found.'); const emptySearchBody = __('Try changing your search settings.'); const resetFilters = () => setSelectedIndex(0); return ( setActiveTabKey(eventKey)} > {__('Package groups')}} >
} isOpen={bulkActionOpen} ouiaId="cv-package-group-filter-bulk-actions-dropdown" isPlain dropdownItems={[ {__('Remove')} ] } /> } />
{(repositories.length || showAffectedRepos) && {__('Affected repositories')}} >
}
); }; CVPackageGroupFilterContent.propTypes = { cvId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, filterId: PropTypes.oneOfType([PropTypes.string, PropTypes.number]).isRequired, showAffectedRepos: PropTypes.bool.isRequired, setShowAffectedRepos: PropTypes.func.isRequired, details: PropTypes.shape({ permissions: PropTypes.shape({}), }).isRequired, }; export default CVPackageGroupFilterContent;