diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js index 6771d02c2b..8d90246cbd 100644 --- a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalFilter.js @@ -16,7 +16,7 @@ import { ReactElement, Fragment, memo, useMemo } from 'react' import PropTypes from 'prop-types' -import { Stack, Button } from '@mui/material' +import { Stack } from '@mui/material' import { Filter } from 'iconoir-react' import { UseFiltersInstanceProps, UseFiltersState } from 'react-table' @@ -33,7 +33,7 @@ import { T } from 'client/constants' const GlobalFilter = memo( (tableProps) => { /** @type {UseFiltersInstanceProps} */ - const { rows, columns, setAllFilters, state } = tableProps + const { rows, columns, state } = tableProps /** @type {UseFiltersState} */ const { filters } = state @@ -57,8 +57,8 @@ const GlobalFilter = memo( } - headerTitle={T.FilterBy} - buttonLabel={T.Filter} + headerTitle={} + buttonLabel={} buttonProps={{ 'data-cy': 'filter-by-button', disableElevation: true, @@ -69,18 +69,10 @@ const GlobalFilter = memo( popperProps={{ placement: 'bottom-end' }} > {() => ( - + {columnsCanFilter.map((column, idx) => ( {column.render('Filter')} ))} - )} diff --git a/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalLabel/Allocator.js b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalLabel/Allocator.js new file mode 100644 index 0000000000..2d6c04b743 --- /dev/null +++ b/src/fireedge/src/client/components/Tables/Enhanced/Utils/GlobalLabel/Allocator.js @@ -0,0 +1,159 @@ +/* ------------------------------------------------------------------------- * + * Copyright 2002-2022, OpenNebula Project, OpenNebula Systems * + * * + * Licensed under the Apache License, Version 2.0 (the "License"); you may * + * not use this file except in compliance with the License. You may obtain * + * a copy of the License at * + * * + * http://www.apache.org/licenses/LICENSE-2.0 * + * * + * Unless required by applicable law or agreed to in writing, software * + * distributed under the License is distributed on an "AS IS" BASIS, * + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * + * See the License for the specific language governing permissions and * + * limitations under the License. * + * ------------------------------------------------------------------------- */ +import { ReactElement, useCallback } from 'react' +import PropTypes from 'prop-types' + +import CheckIcon from 'iconoir-react/dist/Check' +import MinusIcon from 'iconoir-react/dist/Minus' +import { styled, debounce, Box, Typography, Autocomplete } from '@mui/material' + +import { + PopperComponent, + StyledInput, +} from 'client/components/Tables/Enhanced/Utils/GlobalLabel/styles' +import { StatusCircle } from 'client/components/Status' +import { getColorFromString } from 'client/models/Helper' +import { Translate, Tr } from 'client/components/HOC' +import { T } from 'client/constants' + +const EmptyIcon = styled((props) => )({ + width: 20, + height: 20, +}) + +const Label = ({ label, indeterminate, selected, ...props }) => ( + + {selected ? : indeterminate ? : } + + + {label} + + +) + +Label.propTypes = { + label: PropTypes.any, + indeterminate: PropTypes.bool, + selected: PropTypes.bool, +} + +/** + * Allocates labels to the selected rows. + * + * @param {object} props - Component props + * @param {string[]} props.labels - The list of available labels + * @param {string} props.selectedLabels - The list of selected labels + * @param {string[]} props.pendingValue - The current value of the filter + * @param {function(any)} props.handleChange - Handle change event + * @param {function()} props.handleClose - Handle close event + * @returns {ReactElement} Allocator component + */ +const LabelAllocator = ({ + labels, + selectedLabels, + pendingValue, + handleChange, + handleClose, +}) => { + const getLabelProps = useCallback( + (label) => { + const labelProps = { label } + + // labels that exists on every row + if (pendingValue[0]?.includes(label)) + return { ...labelProps, selected: true } + + // labels to remove from every row + if (pendingValue[1]?.includes(label)) { + return { ...labelProps, selected: false } + } + + return selectedLabels.reduce((res, rowLabels) => { + const hasLabel = rowLabels.includes(label) + const prevSelected = [true, undefined].includes(res.selected) + + hasLabel + ? (res.indeterminate = !prevSelected) + : (res.indeterminate ||= res.selected) + + return { ...res, selected: hasLabel && prevSelected } + }, labelProps) + }, + [pendingValue, selectedLabels] + ) + + const handleLabelChange = useCallback( + debounce((event, newValue, reason) => { + const changeFn = { + selectOption: ([, toRemove = []] = []) => [ + newValue, + toRemove?.filter((label) => !newValue.includes(label)), + ], + removeOption: ([toAdd = [], toRemove = []] = []) => { + const prevToAdd = toAdd?.filter((label) => !newValue.includes(label)) + const newToRemove = [...toRemove, ...prevToAdd] + + return [newValue, [...new Set(newToRemove)]] + }, + }[reason] + + changeFn && handleChange(changeFn) + }, 200), + [handleChange] + ) + + return ( + reason === 'escape' && handleClose()} + onChange={handleLabelChange} + disableCloseOnSelect + PopperComponent={PopperComponent} + renderTags={() => null} + noOptionsText={} + renderOption={(props, label) => ( +