Merge branch 'features/media-lib' of github.com:strapi/strapi into media-lib/wysiwyg

This commit is contained in:
soupette 2020-04-10 14:14:34 +02:00
commit 3553025d59
17 changed files with 335 additions and 167 deletions

View File

@ -15,6 +15,7 @@ import CardControl from '../CardControl';
const BrowseAssets = () => { const BrowseAssets = () => {
const { const {
allowedTypes,
count, count,
files, files,
goTo, goTo,
@ -136,6 +137,7 @@ const BrowseAssets = () => {
onChange={handleFileSelection} onChange={handleFileSelection}
selectedItems={selectedFiles} selectedItems={selectedFiles}
onCardClick={handleListCardClick} onCardClick={handleListCardClick}
allowedTypes={allowedTypes}
smallCards smallCards
renderCardControl={renderCardControl} renderCardControl={renderCardControl}
/> />

View File

@ -1,6 +1,7 @@
import React, { memo } from 'react'; import React, { memo } from 'react';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { formatBytes, getExtension, getType } from '../../utils'; import { useGlobalContext } from 'strapi-helper-plugin';
import { formatBytes, getExtension, getType, getTrad } from '../../utils';
import Flex from '../Flex'; import Flex from '../Flex';
import Text from '../Text'; import Text from '../Text';
@ -15,6 +16,7 @@ import Wrapper from '../CardWrapper';
const Card = ({ const Card = ({
id, id,
isDisabled,
checked, checked,
children, children,
errorMessage, errorMessage,
@ -33,15 +35,21 @@ const Card = ({
withFileCaching, withFileCaching,
withoutFileInfo, withoutFileInfo,
}) => { }) => {
const { formatMessage } = useGlobalContext();
const fileSize = formatBytes(size, 0); const fileSize = formatBytes(size, 0);
const fileType = mime || type; const fileType = mime || type;
const handleClick = () => { const handleClick = () => {
onClick(id); if (!isDisabled) {
onClick(id);
}
}; };
return ( return (
<Wrapper onClick={handleClick}> <Wrapper
title={isDisabled ? formatMessage({ id: getTrad('list.assets.type-not-allowed') }) : null}
onClick={handleClick}
>
<CardImgWrapper checked={checked} small={small}> <CardImgWrapper checked={checked} small={small}>
<CardPreview <CardPreview
hasError={hasError} hasError={hasError}
@ -84,6 +92,7 @@ Card.defaultProps = {
children: null, children: null,
errorMessage: null, errorMessage: null,
id: null, id: null,
isDisabled: false,
hasError: false, hasError: false,
hasIcon: false, hasIcon: false,
height: null, height: null,
@ -102,6 +111,7 @@ Card.defaultProps = {
Card.propTypes = { Card.propTypes = {
id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), id: PropTypes.oneOfType([PropTypes.string, PropTypes.number]),
isDisabled: PropTypes.bool,
checked: PropTypes.bool, checked: PropTypes.bool,
children: PropTypes.node, children: PropTypes.node,
errorMessage: PropTypes.string, errorMessage: PropTypes.string,

View File

@ -11,10 +11,12 @@ const Wrapper = styled.div`
`; `;
Wrapper.defaultProps = { Wrapper.defaultProps = {
isDisabled: false,
isDraggable: false, isDraggable: false,
}; };
Wrapper.propTypes = { Wrapper.propTypes = {
isDisabled: PropTypes.bool,
isDraggable: PropTypes.bool, isDraggable: PropTypes.bool,
}; };

View File

@ -8,7 +8,7 @@ import Padded from '../Padded';
const Filters = ({ onChange, onClick, filters }) => { const Filters = ({ onChange, onClick, filters }) => {
return ( return (
<> <>
<FiltersPicker filters={filters} onChange={onChange} /> <FiltersPicker onChange={onChange} />
<Padded left size="sm" /> <Padded left size="sm" />
<FiltersList filters={filters} onClick={onClick} /> <FiltersList filters={filters} onClick={onClick} />
</> </>

View File

@ -12,7 +12,7 @@ import InputWrapper from './InputWrapper';
import FilterButton from './FilterButton'; import FilterButton from './FilterButton';
import FilterInput from './FilterInput'; import FilterInput from './FilterInput';
const FiltersCard = ({ onChange, filters }) => { const FiltersCard = ({ onChange }) => {
const { plugins } = useGlobalContext(); const { plugins } = useGlobalContext();
const timestamps = getFileModelTimestamps(plugins); const timestamps = getFileModelTimestamps(plugins);
const [state, dispatch] = useReducer(reducer, initialState, () => init(initialState, timestamps)); const [state, dispatch] = useReducer(reducer, initialState, () => init(initialState, timestamps));
@ -20,9 +20,7 @@ const FiltersCard = ({ onChange, filters }) => {
const type = filtersForm[name].type; const type = filtersForm[name].type;
const filtersOptions = getFilterType(type); const filtersOptions = getFilterType(type);
const options = ['image', 'video', 'file'].filter( const options = ['image', 'video', 'file'];
f => !filters.find(e => e.value === f && e.isDisabled)
);
const handleChange = ({ target: { name, value } }) => { const handleChange = ({ target: { name, value } }) => {
dispatch({ dispatch({
@ -89,12 +87,10 @@ const FiltersCard = ({ onChange, filters }) => {
}; };
FiltersCard.defaultProps = { FiltersCard.defaultProps = {
filters: [],
onChange: () => {}, onChange: () => {},
}; };
FiltersCard.propTypes = { FiltersCard.propTypes = {
filters: PropTypes.arrayOf(PropTypes.object),
onChange: PropTypes.func, onChange: PropTypes.func,
}; };

View File

@ -9,7 +9,7 @@ import Picker from '../Picker';
import formatFilter from './utils/formatFilter'; import formatFilter from './utils/formatFilter';
const FiltersPicker = ({ onChange, filters }) => { const FiltersPicker = ({ onChange }) => {
const handleChange = ({ target: { value } }) => { const handleChange = ({ target: { value } }) => {
onChange({ target: { name: 'filters', value: formatFilter(value) } }); onChange({ target: { name: 'filters', value: formatFilter(value) } });
}; };
@ -25,7 +25,6 @@ const FiltersPicker = ({ onChange, filters }) => {
)} )}
renderSectionContent={onToggle => ( renderSectionContent={onToggle => (
<FiltersCard <FiltersCard
filters={filters}
onChange={e => { onChange={e => {
handleChange(e); handleChange(e);
onToggle(); onToggle();
@ -38,12 +37,10 @@ const FiltersPicker = ({ onChange, filters }) => {
}; };
FiltersPicker.defaultProps = { FiltersPicker.defaultProps = {
filters: [],
onChange: () => {}, onChange: () => {},
}; };
FiltersPicker.propTypes = { FiltersPicker.propTypes = {
filters: PropTypes.arrayOf(PropTypes.object),
onChange: PropTypes.func, onChange: PropTypes.func,
}; };

View File

@ -3,7 +3,7 @@ import PropTypes from 'prop-types';
import { Checkbox } from '@buffetjs/core'; import { Checkbox } from '@buffetjs/core';
import { get } from 'lodash'; import { get } from 'lodash';
import { prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin'; import { prefixFileUrlWithBackendUrl } from 'strapi-helper-plugin';
import { getTrad } from '../../utils'; import { getTrad, getType } from '../../utils';
import Card from '../Card'; import Card from '../Card';
import CardControlsWrapper from '../CardControlsWrapper'; import CardControlsWrapper from '../CardControlsWrapper';
import ListWrapper from '../ListWrapper'; import ListWrapper from '../ListWrapper';
@ -12,6 +12,7 @@ import ListCell from './ListCell';
import ListRow from './ListRow'; import ListRow from './ListRow';
const List = ({ const List = ({
allowedTypes,
clickable, clickable,
data, data,
onChange, onChange,
@ -23,7 +24,7 @@ const List = ({
}) => { }) => {
const selectedAssets = selectedItems.length; const selectedAssets = selectedItems.length;
const handleClick = e => { const handleCheckboxClick = e => {
e.stopPropagation(); e.stopPropagation();
}; };
@ -40,12 +41,15 @@ const List = ({
{data.map(item => { {data.map(item => {
const { id } = item; const { id } = item;
const url = get(item, ['formats', 'thumbnail', 'url'], item.url); const url = get(item, ['formats', 'thumbnail', 'url'], item.url);
const isAllowed =
allowedTypes.length > 0 ? allowedTypes.includes(getType(item.mime)) : true;
const checked = selectedItems.findIndex(file => file.id === id) !== -1; const checked = selectedItems.findIndex(file => file.id === id) !== -1;
const fileUrl = prefixFileUrlWithBackendUrl(url); const fileUrl = prefixFileUrlWithBackendUrl(url);
return ( return (
<ListCell key={id}> <ListCell key={id}>
<Card <Card
isDisabled={!isAllowed}
checked={checked} checked={checked}
{...item} {...item}
hasIcon={clickable} hasIcon={clickable}
@ -55,14 +59,16 @@ const List = ({
> >
{(checked || canSelect) && ( {(checked || canSelect) && (
<> <>
<CardControlsWrapper leftAlign className="card-control-wrapper"> {isAllowed && (
<Checkbox <CardControlsWrapper leftAlign className="card-control-wrapper">
name={`${id}`} <Checkbox
onChange={onChange} name={`${id}`}
onClick={handleClick} onChange={onChange}
value={checked} onClick={handleCheckboxClick}
/> value={checked}
</CardControlsWrapper> />
</CardControlsWrapper>
)}
{renderCardControl && ( {renderCardControl && (
<CardControlsWrapper className="card-control-wrapper"> <CardControlsWrapper className="card-control-wrapper">
{renderCardControl(id)} {renderCardControl(id)}
@ -80,6 +86,7 @@ const List = ({
}; };
List.defaultProps = { List.defaultProps = {
allowedTypes: [],
clickable: false, clickable: false,
canSelect: true, canSelect: true,
data: [], data: [],
@ -91,6 +98,7 @@ List.defaultProps = {
}; };
List.propTypes = { List.propTypes = {
allowedTypes: PropTypes.array,
clickable: PropTypes.bool, clickable: PropTypes.bool,
canSelect: PropTypes.bool, canSelect: PropTypes.bool,
data: PropTypes.array, data: PropTypes.array,

View File

@ -1,5 +1,5 @@
import React, { useReducer, useState, useRef, useEffect } from 'react'; import React, { useReducer, useState, useRef, useEffect } from 'react';
import { includes, isEmpty, toString } from 'lodash'; import { includes, isEmpty, toString, isEqual, intersectionWith } from 'lodash';
import { useHistory, useLocation } from 'react-router-dom'; import { useHistory, useLocation } from 'react-router-dom';
import { Header } from '@buffetjs/custom'; import { Header } from '@buffetjs/custom';
import { useDebounce } from '@buffetjs/hooks'; import { useDebounce } from '@buffetjs/hooks';
@ -183,9 +183,15 @@ const HomePage = () => {
let updatedQueryParams = generateNewSearch({ [name]: value }); let updatedQueryParams = generateNewSearch({ [name]: value });
if (name === 'filters') { if (name === 'filters') {
const filters = [...generateFiltersFromSearch(search), value]; const existingFilters = generateFiltersFromSearch(search);
const canAddFilter = intersectionWith(existingFilters, [value], isEqual).length === 0;
updatedQueryParams = generateNewSearch({ [name]: existingFilters });
updatedQueryParams = generateNewSearch({ [name]: filters }); if (canAddFilter) {
const filters = [...existingFilters, value];
updatedQueryParams = generateNewSearch({ [name]: filters });
}
} }
if (name === '_limit') { if (name === '_limit') {

View File

@ -20,13 +20,6 @@ const InputModal = ({
step, step,
}) => { }) => {
const singularTypes = allowedTypes.map(type => type.substring(0, type.length - 1)); const singularTypes = allowedTypes.map(type => type.substring(0, type.length - 1));
const typesToDisable = ['video', 'image', 'file'].filter(f => !singularTypes.includes(f));
const nContainsFilters = typesToDisable.map(type => ({
name: 'mime',
filter: '_ncontains',
value: type,
isDisabled: true,
}));
return ( return (
<DndProvider backend={HTML5Backend}> <DndProvider backend={HTML5Backend}>
@ -35,7 +28,6 @@ const InputModal = ({
onClosed={onClosed} onClosed={onClosed}
initialFilesToUpload={filesToUpload} initialFilesToUpload={filesToUpload}
initialFileToEdit={fileToEdit} initialFileToEdit={fileToEdit}
initialFilters={nContainsFilters}
isOpen={isOpen} isOpen={isOpen}
multiple={multiple} multiple={multiple}
noNavigation={noNavigation} noNavigation={noNavigation}

View File

@ -12,6 +12,7 @@ import {
createNewFilesToUploadArray, createNewFilesToUploadArray,
urlSchema, urlSchema,
getFileModelTimestamps, getFileModelTimestamps,
formatFilters,
} from '../../utils'; } from '../../utils';
import InputModalStepperContext from '../../contexts/InputModal/InputModalDataManager'; import InputModalStepperContext from '../../contexts/InputModal/InputModalDataManager';
import init from './init'; import init from './init';
@ -24,7 +25,6 @@ const InputModalStepperProvider = ({
children, children,
initialFilesToUpload, initialFilesToUpload,
initialFileToEdit, initialFileToEdit,
initialFilters,
isOpen, isOpen,
multiple, multiple,
noNavigation, noNavigation,
@ -39,6 +39,7 @@ const InputModalStepperProvider = ({
const [reducerState, dispatch] = useReducer(reducer, initialState, state => const [reducerState, dispatch] = useReducer(reducer, initialState, state =>
init({ init({
...state, ...state,
allowedTypes,
currentStep: step, currentStep: step,
fileToEdit: initialFileToEdit, fileToEdit: initialFileToEdit,
selectedFiles: Array.isArray(selectedFiles) ? selectedFiles : [selectedFiles], selectedFiles: Array.isArray(selectedFiles) ? selectedFiles : [selectedFiles],
@ -50,7 +51,6 @@ const InputModalStepperProvider = ({
: [], : [],
params: { params: {
...state.params, ...state.params,
filters: initialFilters,
_sort: `${updated_at}:DESC`, _sort: `${updated_at}:DESC`,
}, },
}) })
@ -294,10 +294,16 @@ const InputModalStepperProvider = ({
handleRemoveFileToUpload(fileIndex); handleRemoveFileToUpload(fileIndex);
}; };
const getFilters = () => {
const compactedParams = compactParams(params);
const searchParams = generateSearchFromFilters(compactedParams, ['_limit', '_sort', '_start']);
return formatFilters(searchParams);
};
const fetchMediaLibFilesCount = async () => { const fetchMediaLibFilesCount = async () => {
const requestURL = getRequestUrl('files/count'); const requestURL = getRequestUrl('files/count');
const compactedParams = compactParams(params); const paramsToSend = getFilters();
const paramsToSend = generateSearchFromFilters(compactedParams, ['_limit', '_sort', '_start']);
try { try {
return await request(`${requestURL}?${paramsToSend}`, { return await request(`${requestURL}?${paramsToSend}`, {
@ -322,8 +328,7 @@ const InputModalStepperProvider = ({
const fetchMediaLibFiles = async () => { const fetchMediaLibFiles = async () => {
const requestURL = getRequestUrl('files'); const requestURL = getRequestUrl('files');
const compactedParams = compactParams(params); const paramsToSend = getFilters();
const paramsToSend = generateSearchFromFilters(compactedParams);
try { try {
return await request(`${requestURL}?${paramsToSend}`, { return await request(`${requestURL}?${paramsToSend}`, {
@ -474,7 +479,6 @@ InputModalStepperProvider.propTypes = {
children: PropTypes.node.isRequired, children: PropTypes.node.isRequired,
initialFilesToUpload: PropTypes.object, initialFilesToUpload: PropTypes.object,
initialFileToEdit: PropTypes.object, initialFileToEdit: PropTypes.object,
initialFilters: PropTypes.arrayOf(PropTypes.object),
isOpen: PropTypes.bool, isOpen: PropTypes.bool,
multiple: PropTypes.bool.isRequired, multiple: PropTypes.bool.isRequired,
noNavigation: PropTypes.bool, noNavigation: PropTypes.bool,
@ -486,7 +490,6 @@ InputModalStepperProvider.propTypes = {
InputModalStepperProvider.defaultProps = { InputModalStepperProvider.defaultProps = {
initialFileToEdit: null, initialFileToEdit: null,
initialFilters: [],
initialFilesToUpload: null, initialFilesToUpload: null,
isOpen: false, isOpen: false,
noNavigation: false, noNavigation: false,

View File

@ -1,5 +1,5 @@
import produce from 'immer'; import produce from 'immer';
import { intersectionWith, differenceWith, unionWith, set } from 'lodash'; import { intersectionWith, differenceWith, unionWith, set, isEqual } from 'lodash';
import { import {
createNewFilesToDownloadArray, createNewFilesToDownloadArray,
@ -30,6 +30,17 @@ const reducer = (state, action) =>
// eslint-disable-next-line consistent-return // eslint-disable-next-line consistent-return
produce(state, draftState => { produce(state, draftState => {
switch (action.type) { switch (action.type) {
case 'ADD_FILES_TO_UPLOAD': {
draftState.filesToUpload = [
...draftState.filesToUpload,
...createNewFilesToUploadArray(action.filesToUpload),
].map((fileToUpload, index) => ({
...fileToUpload,
originalIndex: index,
}));
draftState.currentStep = action.nextStep;
break;
}
case 'ADD_URLS_TO_FILES_TO_UPLOAD': { case 'ADD_URLS_TO_FILES_TO_UPLOAD': {
draftState.filesToUpload = [ draftState.filesToUpload = [
...draftState.filesToUpload, ...draftState.filesToUpload,
@ -43,12 +54,32 @@ const reducer = (state, action) =>
break; break;
} }
case 'CLEAN_FILES_ERROR': {
draftState.filesToUpload.forEach((fileToUpload, index) => {
draftState.filesToUpload[index] = {
...fileToUpload,
hasError: false,
errorMessage: null,
};
});
break;
}
case 'CLEAR_FILES_TO_UPLOAD_AND_DOWNLOAD': { case 'CLEAR_FILES_TO_UPLOAD_AND_DOWNLOAD': {
draftState.filesToUpload = []; draftState.filesToUpload = [];
draftState.filesToDownload = []; draftState.filesToDownload = [];
break; break;
} }
case 'EDIT_EXISTING_FILE': {
const index = draftState.selectedFiles.findIndex(
selectedFile => selectedFile.id === action.file.id
);
if (index !== -1) {
draftState.selectedFiles[index] = action.file;
}
break;
}
case 'FILE_DOWNLOADED': { case 'FILE_DOWNLOADED': {
const index = state.filesToUpload.findIndex(file => file.tempId === action.fileTempId); const index = state.filesToUpload.findIndex(file => file.tempId === action.fileTempId);
@ -60,32 +91,13 @@ const reducer = (state, action) =>
break; break;
} }
case 'ON_CHANGE': {
set(draftState.fileToEdit, action.keys.split('.'), action.value);
break;
}
case 'ON_CHANGE_URLS_TO_DOWNLOAD': {
set(draftState, ['filesToDownload'], action.value);
break;
}
case 'GET_DATA_SUCCEEDED': { case 'GET_DATA_SUCCEEDED': {
draftState.files = action.files; draftState.files = action.files;
draftState.count = action.countData.count; draftState.count = action.countData.count;
break; break;
} }
case 'SET_PARAM': { case 'GO_TO': {
const { name, value } = action.param; draftState.currentStep = action.to;
if (name === 'filters') {
draftState.params.filters.push(value);
break;
}
if (name === '_limit') {
draftState.params._start = 0;
}
draftState.params[name] = value;
break; break;
} }
case 'MOVE_ASSET': { case 'MOVE_ASSET': {
@ -97,6 +109,18 @@ const reducer = (state, action) =>
break; break;
} }
case 'ON_ABORT_UPLOAD': {
draftState.fileToEdit.isUploading = false;
break;
}
case 'ON_CHANGE': {
set(draftState.fileToEdit, action.keys.split('.'), action.value);
break;
}
case 'ON_CHANGE_URLS_TO_DOWNLOAD': {
set(draftState, ['filesToDownload'], action.value);
break;
}
case 'ON_FILE_SELECTION': { case 'ON_FILE_SELECTION': {
const { id } = action; const { id } = action;
const stringId = id.toString(); const stringId = id.toString();
@ -111,71 +135,8 @@ const reducer = (state, action) =>
draftState.selectedFiles.push(fileToStore); draftState.selectedFiles.push(fileToStore);
break; break;
} }
case 'TOGGLE_SELECT_ALL': { case 'ON_SUBMIT_EDIT_EXISTING_FILE': {
const comparator = (first, second) => first.id === second.id; draftState.fileToEdit.isUploading = true;
const isSelected =
intersectionWith(state.selectedFiles, state.files, comparator).length ===
state.files.length;
if (isSelected) {
draftState.selectedFiles = differenceWith(state.selectedFiles, state.files, comparator);
break;
}
draftState.selectedFiles = unionWith(state.selectedFiles, state.files, comparator);
break;
}
case 'SET_FILE_ERROR': {
draftState.filesToUpload.forEach((fileToUpload, index) => {
if (fileToUpload.originalIndex === action.fileIndex) {
draftState.filesToUpload[index] = {
...draftState.filesToUpload[index],
isUploading: false,
hasError: true,
errorMessage: action.errorMessage,
};
}
});
break;
}
case 'REMOVE_FILTER': {
const { filterToRemove } = action;
draftState.params.filters.splice(filterToRemove, 1);
break;
}
case 'GO_TO': {
draftState.currentStep = action.to;
break;
}
case 'RESET_PROPS': {
if (action.defaultSort) {
draftState.params._sort = action.defaultSort;
} else {
return initialState;
}
break;
}
case 'SET_FILES_UPLOADING_STATE': {
draftState.filesToUpload.forEach((fileToUpload, index) => {
draftState.filesToUpload[index] = {
...fileToUpload,
isUploading: true,
hasError: false,
errorMessage: null,
};
});
break;
}
case 'ADD_FILES_TO_UPLOAD': {
draftState.filesToUpload = [
...draftState.filesToUpload,
...createNewFilesToUploadArray(action.filesToUpload),
].map((fileToUpload, index) => ({
...fileToUpload,
originalIndex: index,
}));
draftState.currentStep = action.nextStep;
break; break;
} }
case 'REMOVE_FILE_TO_UPLOAD': { case 'REMOVE_FILE_TO_UPLOAD': {
@ -195,30 +156,37 @@ const reducer = (state, action) =>
draftState.filesToUpload.splice(index, 1); draftState.filesToUpload.splice(index, 1);
break; break;
} }
case 'REMOVE_FILTER': {
const { filterToRemove } = action;
draftState.params.filters.splice(filterToRemove, 1);
break;
}
case 'RESET_PROPS': {
if (action.defaultSort) {
draftState.params._sort = action.defaultSort;
} else {
return initialState;
}
break;
}
case 'SET_CROP_RESULT': { case 'SET_CROP_RESULT': {
draftState.fileToEdit.file = action.blob; draftState.fileToEdit.file = action.blob;
break; break;
} }
case 'CLEAN_FILES_ERROR': { case 'SET_FILE_ERROR': {
draftState.filesToUpload.forEach((fileToUpload, index) => { draftState.filesToUpload.forEach((fileToUpload, index) => {
draftState.filesToUpload[index] = { if (fileToUpload.originalIndex === action.fileIndex) {
...fileToUpload, draftState.filesToUpload[index] = {
hasError: false, ...draftState.filesToUpload[index],
errorMessage: null, isUploading: false,
}; hasError: true,
errorMessage: action.errorMessage,
};
}
}); });
break; break;
} }
case 'SET_NEW_FILE_TO_EDIT': {
draftState.fileToEdit = draftState.filesToUpload[action.fileIndex];
break;
}
case 'SET_FILE_TO_EDIT': {
draftState.fileToEdit = formatFileForEditing(
state.files.find(file => file.id.toString() === action.fileId.toString())
);
break;
}
case 'SET_FILE_TO_DOWNLOAD_ERROR': { case 'SET_FILE_TO_DOWNLOAD_ERROR': {
const index = state.filesToUpload.findIndex(file => file.tempId === action.fileTempId); const index = state.filesToUpload.findIndex(file => file.tempId === action.fileTempId);
@ -231,20 +199,10 @@ const reducer = (state, action) =>
break; break;
} }
case 'SET_FORM_DISABLED': { case 'SET_FILE_TO_EDIT': {
draftState.isFormDisabled = action.isFormDisabled; draftState.fileToEdit = formatFileForEditing(
break; state.files.find(file => file.id.toString() === action.fileId.toString())
} );
case 'ON_ABORT_UPLOAD': {
draftState.fileToEdit.isUploading = false;
break;
}
case 'TOGGLE_MODAL_WARNING': {
draftState.isWarningDeleteOpen = !state.isWarningDeleteOpen;
break;
}
case 'ON_SUBMIT_EDIT_EXISTING_FILE': {
draftState.fileToEdit.isUploading = true;
break; break;
} }
case 'SET_FILE_TO_EDIT_ERROR': { case 'SET_FILE_TO_EDIT_ERROR': {
@ -253,14 +211,61 @@ const reducer = (state, action) =>
draftState.fileToEdit.errorMessage = action.errorMessage; draftState.fileToEdit.errorMessage = action.errorMessage;
break; break;
} }
case 'EDIT_EXISTING_FILE': { case 'SET_FILES_UPLOADING_STATE': {
const index = draftState.selectedFiles.findIndex( draftState.filesToUpload.forEach((fileToUpload, index) => {
selectedFile => selectedFile.id === action.file.id draftState.filesToUpload[index] = {
); ...fileToUpload,
isUploading: true,
hasError: false,
errorMessage: null,
};
});
break;
}
case 'SET_FORM_DISABLED': {
draftState.isFormDisabled = action.isFormDisabled;
break;
}
case 'SET_NEW_FILE_TO_EDIT': {
draftState.fileToEdit = draftState.filesToUpload[action.fileIndex];
break;
}
case 'SET_PARAM': {
const { name, value } = action.param;
if (index !== -1) { if (name === 'filters') {
draftState.selectedFiles[index] = action.file; const canAddFilter =
intersectionWith(state.params.filters, [value], isEqual).length === 0;
if (canAddFilter) {
draftState.params.filters.push(value);
}
break;
} }
if (name === '_limit') {
draftState.params._start = 0;
}
draftState.params[name] = value;
break;
}
case 'TOGGLE_MODAL_WARNING': {
draftState.isWarningDeleteOpen = !state.isWarningDeleteOpen;
break;
}
case 'TOGGLE_SELECT_ALL': {
const comparator = (first, second) => first.id === second.id;
const isSelected =
intersectionWith(state.selectedFiles, state.files, comparator).length ===
state.files.length;
if (isSelected) {
draftState.selectedFiles = differenceWith(state.selectedFiles, state.files, comparator);
break;
}
draftState.selectedFiles = unionWith(state.selectedFiles, state.files, comparator);
break; break;
} }

View File

@ -1933,4 +1933,105 @@ describe('UPLOAD | containers | ModalStepper | reducer', () => {
expect(reducer(state, action)).toEqual(expected); expect(reducer(state, action)).toEqual(expected);
}); });
}); });
describe('SET_PARAM', () => {
it('should set the _start param to 0 if the pagination limit changed', () => {
const action = {
type: 'SET_PARAM',
param: {
name: '_limit',
value: 50,
},
};
const state = {
params: {
_start: 10,
},
};
const expected = {
params: {
_start: 0,
_limit: 50,
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('should add filter to params', () => {
const action = {
type: 'SET_PARAM',
param: {
name: 'filters',
value: {
name: 'mime',
filter: '_contains',
value: 'image',
},
},
};
const state = {
params: {
_start: 0,
filters: [],
},
};
const expected = {
params: {
_start: 0,
filters: [
{
name: 'mime',
filter: '_contains',
value: 'image',
},
],
},
};
expect(reducer(state, action)).toEqual(expected);
});
it('should not add filter to params if it is already exist', () => {
const action = {
type: 'SET_PARAM',
param: {
name: 'filters',
value: {
name: 'mime',
filter: '_contains',
value: 'image',
},
},
};
const state = {
params: {
_start: 0,
_limit: 50,
filters: [
{
name: 'mime',
filter: '_contains',
value: 'image',
},
],
},
};
const expected = {
params: {
_start: 0,
_limit: 50,
filters: [
{
name: 'mime',
filter: '_contains',
value: 'image',
},
],
},
};
expect(reducer(state, action)).toEqual(expected);
});
});
}); });

View File

@ -30,6 +30,7 @@
"list.assets-empty.title": "There is no asset yet", "list.assets-empty.title": "There is no asset yet",
"list.assets-empty.title-withSearch": "There is no asset with the applied filters", "list.assets-empty.title-withSearch": "There is no asset with the applied filters",
"list.assets-empty.subtitle": "Add a first one to the list.", "list.assets-empty.subtitle": "Add a first one to the list.",
"list.assets.type-not-allowed": "This type of file is not allowed.",
"list.assets.selected.plural": "{number} assets selected", "list.assets.selected.plural": "{number} assets selected",
"list.assets.selected.singular": "{number} asset selected", "list.assets.selected.singular": "{number} asset selected",
"modal.header.browse": "Upload assets", "modal.header.browse": "Upload assets",

View File

@ -0,0 +1,23 @@
const formatFilters = params => {
const indexOfFileFilterContains = params.indexOf('mime_contains=file');
const indexOfFileFilterNContains = params.indexOf('mime_ncontains=file');
let paramsToReturn = params;
if (indexOfFileFilterContains !== -1) {
paramsToReturn = paramsToReturn.replace(
'mime_contains=file',
'mime_ncontains=image&mime_ncontains=video'
);
}
if (indexOfFileFilterNContains !== -1) {
paramsToReturn = paramsToReturn.replace(
'mime_ncontains=file',
'mime_contains=image&mime_contains=video'
);
}
return paramsToReturn;
};
export default formatFilters;

View File

@ -6,6 +6,7 @@ export { default as createNewFilesToDownloadArray } from './createNewFilesToDown
export { default as createNewFilesToUploadArray } from './createNewFilesToUploadArray'; export { default as createNewFilesToUploadArray } from './createNewFilesToUploadArray';
export { default as formatBytes } from './formatBytes'; export { default as formatBytes } from './formatBytes';
export { default as formatFileForEditing } from './formatFileForEditing'; export { default as formatFileForEditing } from './formatFileForEditing';
export { default as formatFilters } from './formatFilters';
export { default as generatePageFromStart } from './generatePageFromStart'; export { default as generatePageFromStart } from './generatePageFromStart';
export { default as generateStartFromPage } from './generateStartFromPage'; export { default as generateStartFromPage } from './generateStartFromPage';
export { default as getExtension } from './getExtension'; export { default as getExtension } from './getExtension';

View File

@ -0,0 +1,21 @@
import formatFilters from '../formatFilters';
describe('UPLOAD | utils | formatFilters', () => {
it('should remove the file filter and add image and video filters', () => {
const stringParams = '&mime_ncontains=file&mime_contains=file';
const actual = formatFilters(stringParams);
const expected =
'&mime_contains=image&mime_contains=video&mime_ncontains=image&mime_ncontains=video';
expect(actual).toEqual(expected);
});
it('should return the string params if there is no file filter', () => {
const stringParams = '&mime_contains=image&mime_contains=video';
const actual = formatFilters(stringParams);
const expected = '&mime_contains=image&mime_contains=video';
expect(actual).toEqual(expected);
});
});