diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/GenericInput.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/GenericInput.js new file mode 100644 index 0000000000..a7baa11484 --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/GenericInput.js @@ -0,0 +1,63 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import moment from 'moment'; +import { DateTime } from '@buffetjs/custom'; +import { DatePicker, InputText, InputNumber, Select, TimePicker } from '@buffetjs/core'; +import { DateWrapper } from './components'; + +function GenericInput({ type, onChange, value, ...rest }) { + switch (type) { + case 'boolean': + return onChange(e.target.value)} value={value} {...rest} />; + + case 'integer': + case 'decimal': + case 'float': + return onChange(e.target.value)} value={value} {...rest} />; + + case 'time': + return onChange(e.target.value)} value={value} {...rest} />; + + /** + * "biginteger" type falls into this section + */ + default: + return onChange(e.target.value)} value={value} {...rest} />; + } +} + +GenericInput.defaultProps = { + value: undefined, +}; + +GenericInput.propTypes = { + onChange: PropTypes.func.isRequired, + type: PropTypes.string.isRequired, + value: PropTypes.any, +}; + +export default GenericInput; diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/components.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/components.js new file mode 100644 index 0000000000..ae3db3e467 --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/components.js @@ -0,0 +1,24 @@ +import { Button } from '@buffetjs/core'; +import styled from 'styled-components'; + +export const StyledButton = styled(Button)` + width: 100%; +`; + +export const FormWrapper = styled.form` + min-width: 330px; + max-width: 400px; + padding: 13px 15px; + + & > * + * { + margin-top: 11px; + } +`; + +export const DateWrapper = styled.div` + display: ${({ type }) => (type === 'datetime' ? 'flex' : 'block')}; + + input { + width: 100%; + } +`; diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/hooks/useAllowedAttributes.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/hooks/useAllowedAttributes.js new file mode 100644 index 0000000000..1d58afe82c --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/hooks/useAllowedAttributes.js @@ -0,0 +1,47 @@ +import get from 'lodash/get'; +import { useRBACProvider, findMatchingPermissions } from '@strapi/helper-plugin'; + +const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamiczone']; + +const useAllowedAttributes = (contentType, slug) => { + const { allPermissions } = useRBACProvider(); + + let timestamps = get(contentType, ['options', 'timestamps']); + + if (!Array.isArray(timestamps)) { + timestamps = []; + } + + const readPermissionsForSlug = findMatchingPermissions(allPermissions, [ + { + action: 'plugins::content-manager.explorer.read', + subject: slug, + }, + ]); + + const readPermissionForAttr = get(readPermissionsForSlug, ['0', 'properties', 'fields'], []); + const attributesArray = Object.keys(get(contentType, ['attributes']), {}); + const allowedAttributes = attributesArray + .filter(attr => { + const current = get(contentType, ['attributes', attr], {}); + + if (!current.type) { + return false; + } + + if (NOT_ALLOWED_FILTERS.includes(current.type)) { + return false; + } + + if (!readPermissionForAttr.includes(attr) && attr !== 'id' && !timestamps.includes(attr)) { + return false; + } + + return true; + }) + .sort(); + + return allowedAttributes; +}; + +export default useAllowedAttributes; diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/index.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/index.js new file mode 100644 index 0000000000..3eea795810 --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/index.js @@ -0,0 +1,114 @@ +import React, { useState } from 'react'; +import PropTypes from 'prop-types'; +import { Picker, Select } from '@buffetjs/core'; +import { + FilterIcon, + getFilterType as comparatorsForType, + useTracking, + useQueryParams, +} from '@strapi/helper-plugin'; +import { FormattedMessage } from 'react-intl'; +import useAllowedAttributes from './hooks/useAllowedAttributes'; +import getTrad from '../../utils/getTrad'; +import formatAttribute from './utils/formatAttribute'; +import getAttributeType from './utils/getAttributeType'; +import GenericInput from './GenericInput'; +import { StyledButton, FormWrapper } from './components'; + +const AttributeFilter = ({ contentType, slug, metaData }) => { + const { trackUsage } = useTracking(); + const [{ query }, setQuery] = useQueryParams(); + + const allowedAttributes = useAllowedAttributes(contentType, slug); + const [attribute, setAttribute] = useState(allowedAttributes[0]); + + const attributeType = getAttributeType(attribute, contentType, metaData); + const comparators = comparatorsForType(attributeType); + const [comparator, setComparator] = useState(comparators[0].value); + + const [value, setValue] = useState(); + + return ( + ( + <> + + + + )} + renderSectionContent={onToggle => { + const handleSubmit = e => { + e.preventDefault(); + + const formattedAttribute = formatAttribute(attribute, metaData); + + /** + * When dealing with a "=" comparator, the filter should have a shape of {'attributeName': 'some value} + * otherwise, it should look like { 'attributeName_comparatorName' : 'some value' } + */ + const newFilter = + comparator === '=' + ? { [formattedAttribute]: value } + : { [`${formattedAttribute}${comparator}`]: value }; + + /** + * Pushing the filter in the URL for later refreshes or fast access + */ + const _where = query._where || []; + _where.push(newFilter); + setQuery({ ...query, _where, page: 1 }); + + /** + * Tracking stuff + */ + const useRelation = _where.some(obj => Object.keys(obj)[0].includes('.')); + trackUsage('didFilterEntries', { useRelation }); + + /** + * Reset to initial state + */ + setAttribute(allowedAttributes[0]); + setComparator(comparators[0].value); + setValue(undefined); + + onToggle(); + }; + + return ( + + setComparator(e.target.value)} + name="comparator" + value={comparator} + options={comparators.map(comparator => ( + + {msg => } + + ))} + /> + + + + + + ); + }} + /> + ); +}; + +AttributeFilter.propTypes = { + contentType: PropTypes.object.isRequired, + metaData: PropTypes.object.isRequired, + slug: PropTypes.string.isRequired, +}; + +export default AttributeFilter; diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/formatAttribute.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/formatAttribute.js new file mode 100644 index 0000000000..efc23ce91f --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/formatAttribute.js @@ -0,0 +1,13 @@ +import get from 'lodash/get'; + +const formatAttribute = (attributeName, metaData) => { + const mainField = get(metaData, [attributeName, 'list', 'mainField', 'name']); + + if (mainField) { + return `${attributeName}.${mainField}`; + } + + return attributeName; +}; + +export default formatAttribute; diff --git a/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/getAttributeType.js b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/getAttributeType.js new file mode 100644 index 0000000000..91d314ee6f --- /dev/null +++ b/packages/core/admin/admin/src/content-manager/components/AttributeFilter/utils/getAttributeType.js @@ -0,0 +1,13 @@ +import get from 'lodash/get'; + +const getAttributeType = (attributeName, contentType, metaData) => { + let attributeType = get(contentType, ['attributes', attributeName, 'type'], ''); + + if (attributeType === 'relation') { + attributeType = get(metaData, [attributeName, 'list', 'mainField', 'schema', 'type'], 'string'); + } + + return attributeType === 'string' ? 'text' : attributeType; +}; + +export default getAttributeType; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPicker/components.js b/packages/core/admin/admin/src/content-manager/components/FilterPicker/components.js deleted file mode 100644 index c3c678e879..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPicker/components.js +++ /dev/null @@ -1,56 +0,0 @@ -import styled from 'styled-components'; - -/* eslint-disable indent */ -const Wrapper = styled.div` - margin-top: -6px; - > div { - padding-top: 2px; - &:not(:first-of-type) { - padding-top: 9px; - padding-bottom: 2px; - &:last-of-type:nth-of-type(even) { - padding-bottom: 11px; - } - } - } -`; - -const Span = styled.span` - vertical-align: text-top; - cursor: pointer; - - &:after { - margin-left: 2px; - content: '\f077'; - font-family: FontAwesome; - font-size: 10px; - } -`; - -const Flex = styled.div` - display: flex; - justify-content: flex-end; - padding: 0 0 10px 30px !important; - margin-top: -10px; - color: #c3c5c8; - font-size: 13px; -`; - -const Div = styled.div` - width: calc(100% + 60px); - margin: ${props => (props.show ? '-100px -30px 30px' : `-${props.number}px -30px 103px`)}; - background: #fff; - box-shadow: 3px 2px 4px #e3e9f3; - padding: 18px 30px 0px 30px; - transition: ${props => { - if (props.anim) { - return props.show - ? 'margin-top .3s ease-out, margin-bottom .2s ease-out' - : 'margin .3s ease-in'; - } - - return ''; - }}; -`; - -export { Div, Flex, Span, Wrapper }; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPicker/index.js b/packages/core/admin/admin/src/content-manager/components/FilterPicker/index.js deleted file mode 100644 index 5ffea07a6a..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPicker/index.js +++ /dev/null @@ -1,256 +0,0 @@ -import React, { memo, useCallback, useMemo, useReducer, useRef } from 'react'; -import { withRouter } from 'react-router'; -import PropTypes from 'prop-types'; -import { capitalize, get } from 'lodash'; -import { Collapse } from 'reactstrap'; -import { FormattedMessage } from 'react-intl'; -import { - PluginHeader, - getFilterType, - useRBACProvider, - findMatchingPermissions, - useTracking, -} from '@strapi/helper-plugin'; -import { formatFiltersToQuery, getTrad } from '../../utils'; -import Container from '../Container'; -import FilterPickerOption from '../FilterPickerOption'; -import { Flex, Span, Wrapper } from './components'; -import init from './init'; -import reducer, { initialState } from './reducer'; - -const NOT_ALLOWED_FILTERS = ['json', 'component', 'media', 'richtext', 'dynamiczone']; - -function FilterPicker({ - contentType, - filters, - isOpen, - metadatas, - name, - toggleFilterPickerState, - setQuery, - slug, -}) { - const { trackUsage } = useTracking(); - const trackUsageRef = useRef(trackUsage); - const { allPermissions } = useRBACProvider(); - const readActionAllowedFields = useMemo(() => { - const matchingPermissions = findMatchingPermissions(allPermissions, [ - { - action: 'plugins::content-manager.explorer.read', - subject: slug, - }, - ]); - - return get(matchingPermissions, ['0', 'properties', 'fields'], []); - }, [allPermissions, slug]); - - let timestamps = get(contentType, ['options', 'timestamps']); - - if (!Array.isArray(timestamps)) { - timestamps = []; - } - - const actions = [ - { - label: getTrad('components.FiltersPickWrapper.PluginHeader.actions.clearAll'), - kind: 'secondary', - onClick: () => { - toggleFilterPickerState(); - setQuery({ _where: [] }, 'remove'); - }, - }, - { - label: getTrad('components.FiltersPickWrapper.PluginHeader.actions.apply'), - kind: 'primary', - type: 'submit', - }, - ]; - - const allowedAttributes = Object.keys(get(contentType, ['attributes']), {}) - .filter(attr => { - const current = get(contentType, ['attributes', attr], {}); - - if (!readActionAllowedFields.includes(attr) && attr !== 'id' && !timestamps.includes(attr)) { - return false; - } - - return !NOT_ALLOWED_FILTERS.includes(current.type) && current.type !== undefined; - }) - .sort() - .map(attr => { - const current = get(contentType, ['attributes', attr], {}); - - return { name: attr, type: current.type, options: current.enum || null }; - }); - - const [state, dispatch] = useReducer(reducer, initialState, () => - init(initialState, allowedAttributes[0] || {}) - ); - - const modifiedData = state.get('modifiedData').toJS(); - const handleChange = ({ target: { name, value } }) => { - dispatch({ - type: 'ON_CHANGE', - keys: name.split('.'), - value, - }); - }; - - const renderTitle = () => ( - - {message => ( - - {capitalize(name)} -  - {message} - - )} - - ); - - const initialFilter = useMemo(() => { - const type = get(allowedAttributes, [0, 'type'], ''); - const [filter] = getFilterType(type); - - let value = ''; - - switch (type) { - case 'boolean': { - value = 'true'; - break; - } - case 'number': { - value = 0; - break; - } - case 'enumeration': { - value = get(allowedAttributes, [0, 'options', 0], ''); - break; - } - default: { - value = ''; - } - } - - const initFilter = { - name: get(allowedAttributes, [0, 'name'], ''), - filter: filter.value, - value, - }; - - return initFilter; - }, [allowedAttributes]); - - // Set the filters when the collapse is opening - const handleEntering = () => { - const currentFilters = filters; - const initialFilters = currentFilters.length ? currentFilters : [initialFilter]; - - dispatch({ - type: 'SET_FILTERS', - initialFilters, - attributes: get(contentType, 'attributes', {}), - }); - }; - - const addFilter = () => { - dispatch({ - type: 'ADD_FILTER', - filter: initialFilter, - }); - }; - - const handleSubmit = useCallback( - e => { - e.preventDefault(); - const nextFilters = formatFiltersToQuery(modifiedData, metadatas); - const useRelation = nextFilters._where.some(obj => Object.keys(obj)[0].includes('.')); - - trackUsageRef.current('didFilterEntries', { useRelation }); - setQuery({ ...nextFilters, page: 1 }); - toggleFilterPickerState(); - }, - [modifiedData, setQuery, toggleFilterPickerState, metadatas] - ); - - const handleRemoveFilter = index => { - if (index === 0 && modifiedData.length === 1) { - toggleFilterPickerState(); - - return; - } - - dispatch({ - type: 'REMOVE_FILTER', - index, - }); - }; - - const getAttributeType = useCallback( - filter => { - const attributeType = get(contentType, ['attributes', filter.name, 'type'], ''); - - if (attributeType === 'relation') { - return get(metadatas, [filter.name, 'list', 'mainField', 'schema', 'type'], 'string'); - } - - return attributeType; - }, - [contentType, metadatas] - ); - - return ( - - -
- - - {modifiedData.map((filter, key) => ( - - ))} - - - - -   - - - -
-
- ); -} - -FilterPicker.defaultProps = { - name: '', -}; - -FilterPicker.propTypes = { - contentType: PropTypes.object.isRequired, - filters: PropTypes.array.isRequired, - isOpen: PropTypes.bool.isRequired, - metadatas: PropTypes.object.isRequired, - name: PropTypes.string, - setQuery: PropTypes.func.isRequired, - slug: PropTypes.string.isRequired, - toggleFilterPickerState: PropTypes.func.isRequired, -}; - -export default withRouter(memo(FilterPicker)); diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPicker/init.js b/packages/core/admin/admin/src/content-manager/components/FilterPicker/init.js deleted file mode 100644 index e5ff56b29d..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPicker/init.js +++ /dev/null @@ -1,25 +0,0 @@ -import { fromJS } from 'immutable'; -import { getFilterType } from '@strapi/helper-plugin'; -import { get } from 'lodash'; - -function init(initialState, { name, type, options }) { - // Create the first filter - const [filter] = getFilterType(type); - let value = ''; - - if (type === 'boolean') { - value = 'true'; - } else if (type === 'number') { - value = 0; - } else if (type === 'enumeration') { - value = get(options, [0], ''); - } - - const initialFilter = { name, filter: filter.value, value }; - - return initialState - .update('initialData', () => fromJS([initialFilter])) - .update('modifiedData', () => fromJS([initialFilter])); -} - -export default init; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPicker/reducer.js b/packages/core/admin/admin/src/content-manager/components/FilterPicker/reducer.js deleted file mode 100644 index 3bfba99be5..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPicker/reducer.js +++ /dev/null @@ -1,58 +0,0 @@ -import { fromJS } from 'immutable'; - -const initialState = fromJS({ - attributes: {}, - initialData: [], - modifiedData: [], -}); - -function reducer(state, action) { - switch (action.type) { - case 'ADD_FILTER': - return state.update('modifiedData', list => list.push(fromJS(action.filter))); - case 'ON_CHANGE': { - const [index, key] = action.keys; - - return state - .updateIn(['modifiedData', ...action.keys], () => { - if (action.value && action.value._isAMomentObject === true) { - return action.value.toISOString(); - } - - return action.value; - }) - .updateIn(['modifiedData', index, 'value'], value => { - if (key === 'name') { - const attribute = state.getIn(['attributes', action.value]); - const attributeType = attribute.get('type'); - - if (attributeType === 'boolean') { - return 'true'; - } - - if (attributeType === 'enumeration') { - return attribute.getIn(['enum', '0']) || ''; - } - - return ''; - } - - return value; - }); - } - case 'REMOVE_FILTER': - return state.removeIn(['modifiedData', action.index]); - case 'RESET_FILTERS': - return initialState; - case 'SET_FILTERS': - return state - .update('attributes', () => fromJS(action.attributes)) - .update('initialData', () => fromJS(action.initialFilters)) - .update('modifiedData', () => fromJS(action.initialFilters)); - default: - return state; - } -} - -export default reducer; -export { initialState }; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Input.js b/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Input.js deleted file mode 100644 index e1c07530f5..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Input.js +++ /dev/null @@ -1,58 +0,0 @@ -/** - * - * InputWithAutoFocus that programatically manage the autofocus of another one - */ - -import React, { memo } from 'react'; -import PropTypes from 'prop-types'; - -import { DateTime } from '@buffetjs/custom'; -import { DatePicker, InputText, InputNumber, Select, TimePicker } from '@buffetjs/core'; -import { InputWrapperDate } from './components'; - -const getInputType = attrType => { - switch (attrType) { - case 'boolean': - return Select; - case 'date': - case 'timestamp': - case 'timestampUpdate': - return DatePicker; - case 'datetime': - return DateTime; - case 'enumeration': - return Select; - case 'integer': - case 'biginteger': - case 'decimal': - case 'float': - return InputNumber; - case 'time': - return TimePicker; - default: - return InputText; - } -}; - -function Input({ type, ...rest }) { - const Component = getInputType(type); - let style = type !== 'time' ? { width: '210px' } : {}; - - if (['integer', 'biginteger', 'float', 'decimal'].includes(type)) { - style = { marginRight: '15px' }; - } - const styles = type === 'boolean' ? { minWidth: '100px', maxWidth: '200px' } : style; - const wrapperStyle = { marginRight: '15px' }; - - return ( - - - - ); -} - -Input.propTypes = { - type: PropTypes.string.isRequired, -}; - -export default memo(Input); diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Option.js b/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Option.js deleted file mode 100644 index 4bb3efc66d..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/Option.js +++ /dev/null @@ -1,14 +0,0 @@ -import React from 'react'; -import { FormattedMessage } from 'react-intl'; -import PropTypes from 'prop-types'; - -const Option = ({ id, value }) => { - return {msg => }; -}; - -Option.propTypes = { - id: PropTypes.string.isRequired, - value: PropTypes.string.isRequired, -}; - -export default Option; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/components.js b/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/components.js deleted file mode 100644 index 74ad959159..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/components.js +++ /dev/null @@ -1,60 +0,0 @@ -import styled from 'styled-components'; - -/* eslint-disable */ - -const Wrapper = styled.div` - min-height: 38px; - border-left: ${props => props.borderLeft && '3px solid #007EFF'}; - padding-left: ${props => (props.borderLeft ? '10px' : '13px')}; - margin-bottom: 0px !important; -`; - -const InputWrapper = styled.div` - display: flex; - input, - select { - margin: 0px 5px !important; - } -`; - -const InputWrapperDate = styled.div` - margin-right: 10px; - span { - left: 5px; - } - .rc-input-number-handler-wrap { - right: -5px !important; - } - .rc-input-number-input-wrap { - max-width: 210px; - overflow: visible; - } - > div { - width: 210px; - } - - ${({ type }) => { - if (type === 'datetime') { - return ` - > div { - width: 300px; - } - - `; - } - }} -`; - -const Input = styled.input` - height: 3.4rem; - margin-top: 0.9rem; - padding-left: 1rem; - background-size: 0 !important; - border: 1px solid #e3e9f3; - border-radius: 0.25rem; - line-height: 3.4rem; - font-size: 1.3rem; - font-family: 'Lato' !important; - box-shadow: 0px 1px 1px rgba(104, 118, 142, 0.05); -`; -export { InputWrapper, Wrapper, InputWrapperDate, Input }; diff --git a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/index.js b/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/index.js deleted file mode 100644 index 93c1560af5..0000000000 --- a/packages/core/admin/admin/src/content-manager/components/FilterPickerOption/index.js +++ /dev/null @@ -1,101 +0,0 @@ -import React, { memo } from 'react'; -import { get, isEmpty } from 'lodash'; -import PropTypes from 'prop-types'; -import { CircleButton, getFilterType } from '@strapi/helper-plugin'; -import { Select } from '@buffetjs/core'; - -import { InputWrapper, Wrapper } from './components'; -import Input from './Input'; -import Option from './Option'; - -const styles = { - select: { - minWidth: '170px', - maxWidth: '200px', - }, - selectMiddle: { - minWidth: '130px', - maxWidth: '200px', - marginLeft: '10px', - marginRight: '10px', - }, -}; - -function FilterPickerOption({ - allowedAttributes, - modifiedData, - index, - onChange, - onClickAddFilter, - onRemoveFilter, - value, - showAddButton, - type, -}) { - const filtersOptions = getFilterType(type); - const currentFilterName = get(modifiedData, [index, 'name'], ''); - const currentFilterData = allowedAttributes.find(attr => attr.name === currentFilterName); - const options = get(currentFilterData, ['options'], null) || ['true', 'false']; - - return ( - - - onRemoveFilter(index)} /> - ( - - - ); -} - -FilterPickerOption.defaultProps = { - allowedAttributes: [], - modifiedData: [], - index: -1, - onChange: () => {}, - onClickAddFilter: () => {}, - onRemoveFilter: () => {}, - value: null, - type: 'string', -}; - -FilterPickerOption.propTypes = { - allowedAttributes: PropTypes.array, - modifiedData: PropTypes.array, - index: PropTypes.number, - onChange: PropTypes.func, - onClickAddFilter: PropTypes.func, - onRemoveFilter: PropTypes.func, - showAddButton: PropTypes.bool.isRequired, - type: PropTypes.string, - value: PropTypes.any, -}; - -export default memo(FilterPickerOption); diff --git a/packages/core/admin/admin/src/content-manager/pages/ListView/components.js b/packages/core/admin/admin/src/content-manager/pages/ListView/components.js index b9d07299ba..2ead6dfe53 100644 --- a/packages/core/admin/admin/src/content-manager/pages/ListView/components.js +++ b/packages/core/admin/admin/src/content-manager/pages/ListView/components.js @@ -1,46 +1,10 @@ import styled from 'styled-components'; -import { Button, FilterIcon as Filter } from '@strapi/helper-plugin'; import RemoveIcon from '../../assets/images/icon-cross-blue.svg'; const Wrapper = styled.div` padding-top: 1px; `; -const FilterIcon = styled(Filter)` - padding: 0 !important; - margin: auto !important; - > g { - stroke: #282b2c; - } -`; - -const AddFilterCta = styled(Button)` - display: flex; - height: 30px; - margin-right: 10px; - padding: 0 10px; - text-align: center; - background-color: #ffffff; - border: 1px solid #e3e9f3; - border-radius: 2px; - line-height: 28px; - font-size: 13px; - font-weight: 500; - font-family: Lato; - -webkit-font-smoothing: antialiased; - cursor: pointer; - &:hover { - background: #f7f8f8; - } - &:focus, - &:active { - outline: 0; - } - > span { - margin-left: 10px; - } -`; - const Img = styled.img` height: 7px; margin: auto; @@ -124,15 +88,4 @@ const Remove = styled.span` } `; -export { - AddFilterCta, - FilterIcon, - FooterWrapper, - Img, - Label, - SelectWrapper, - FilterWrapper, - Separator, - Remove, - Wrapper, -}; +export { FooterWrapper, Img, Label, SelectWrapper, FilterWrapper, Separator, Remove, Wrapper }; diff --git a/packages/core/admin/admin/src/content-manager/pages/ListView/index.js b/packages/core/admin/admin/src/content-manager/pages/ListView/index.js index d0ca52b4eb..e11f4636e2 100644 --- a/packages/core/admin/admin/src/content-manager/pages/ListView/index.js +++ b/packages/core/admin/admin/src/content-manager/pages/ListView/index.js @@ -3,7 +3,7 @@ import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import { bindActionCreators, compose } from 'redux'; import { get, isEmpty } from 'lodash'; -import { FormattedMessage, useIntl } from 'react-intl'; +import { useIntl } from 'react-intl'; import { useHistory, useLocation } from 'react-router-dom'; import { Header } from '@buffetjs/custom'; import { Flex, Padded } from '@buffetjs/core'; @@ -26,11 +26,10 @@ import permissions from '../../../permissions'; import { formatFiltersFromQuery, getRequestUrl, getTrad } from '../../utils'; import Container from '../../components/Container'; import CustomTable from '../../components/CustomTable'; -import FilterPicker from '../../components/FilterPicker'; import Search from '../../components/Search'; import ListViewProvider from '../../components/ListViewProvider'; import InjectionZoneList from '../../components/InjectionZoneList'; -import { AddFilterCta, FilterIcon, Wrapper } from './components'; +import { Wrapper } from './components'; import FieldPicker from './FieldPicker'; import Filter from './Filter'; import Footer from './Footer'; @@ -51,6 +50,7 @@ import { } from './actions'; import makeSelectListView from './selectors'; import { getAllAllowedHeaders, getFirstSortableHeader, buildQueryString } from './utils'; +import AttributeFilter from '../../components/AttributeFilter'; const cmPermissions = permissions.contentManager; @@ -395,16 +395,6 @@ function ListView({ toggleModalDeleteAll={handleToggleModalDeleteAll} setQuery={setQuery} > - {!isFilterPickerOpen &&
} {isSearchable && canRead && ( @@ -432,10 +422,13 @@ function ListView({
{isFilterable && ( <> - - - - + + + {filters.map(({ filter: filterName, name, value }, key) => (