mirror of
https://github.com/strapi/strapi.git
synced 2025-11-09 06:40:42 +00:00
Merge pull request #5610 from strapi/features/media-lib-fix-bugs
ML fix front-end bugs
This commit is contained in:
commit
6cdf0a7891
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"kind": "collectionType",
|
||||||
"connection": "default",
|
"connection": "default",
|
||||||
"collectionName": "addresses",
|
"collectionName": "addresses",
|
||||||
"info": {
|
"info": {
|
||||||
@ -7,14 +8,13 @@
|
|||||||
},
|
},
|
||||||
"options": {
|
"options": {
|
||||||
"increments": true,
|
"increments": true,
|
||||||
"timestamps": ["created_at", "updated_at"],
|
"timestamps": [
|
||||||
|
"created_at",
|
||||||
|
"updated_at"
|
||||||
|
],
|
||||||
"comment": ""
|
"comment": ""
|
||||||
},
|
},
|
||||||
"attributes": {
|
"attributes": {
|
||||||
"geolocation": {
|
|
||||||
"type": "json",
|
|
||||||
"required": true
|
|
||||||
},
|
|
||||||
"city": {
|
"city": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"required": true
|
"required": true
|
||||||
@ -30,16 +30,22 @@
|
|||||||
"cover": {
|
"cover": {
|
||||||
"model": "file",
|
"model": "file",
|
||||||
"via": "related",
|
"via": "related",
|
||||||
|
"allowedTypes": [
|
||||||
|
"files",
|
||||||
|
"images",
|
||||||
|
"videos"
|
||||||
|
],
|
||||||
"plugin": "upload",
|
"plugin": "upload",
|
||||||
"required": false,
|
"required": false
|
||||||
"allowedTypes": ["images", "cover"]
|
|
||||||
},
|
},
|
||||||
"images": {
|
"images": {
|
||||||
"collection": "file",
|
"collection": "file",
|
||||||
"via": "related",
|
"via": "related",
|
||||||
|
"allowedTypes": [
|
||||||
|
"images"
|
||||||
|
],
|
||||||
"plugin": "upload",
|
"plugin": "upload",
|
||||||
"required": false,
|
"required": false
|
||||||
"allowedTypes": []
|
|
||||||
},
|
},
|
||||||
"full_name": {
|
"full_name": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"kind": "collectionType",
|
||||||
"connection": "default",
|
"connection": "default",
|
||||||
"collectionName": "categories",
|
"collectionName": "categories",
|
||||||
"info": {
|
"info": {
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
// provider: 'aws-s3',
|
// provider: 'cloudinary',
|
||||||
// providerOptions: {
|
// providerOptions: {
|
||||||
// cloud_name: '',
|
// cloud_name: 'cloud-name',
|
||||||
// api_key: '',
|
// api_key: 'api-key',
|
||||||
// api_secret: '',
|
// api_secret: 'api-secret',
|
||||||
// },
|
// },
|
||||||
};
|
};
|
||||||
|
|||||||
@ -29,6 +29,7 @@
|
|||||||
"strapi-plugin-users-permissions": "3.0.0-beta.19.3",
|
"strapi-plugin-users-permissions": "3.0.0-beta.19.3",
|
||||||
"strapi-provider-email-mailgun": "3.0.0-beta.19.3",
|
"strapi-provider-email-mailgun": "3.0.0-beta.19.3",
|
||||||
"strapi-provider-upload-aws-s3": "3.0.0-beta.19.3",
|
"strapi-provider-upload-aws-s3": "3.0.0-beta.19.3",
|
||||||
|
"strapi-provider-upload-cloudinary": "3.0.0-beta.19.3",
|
||||||
"strapi-utils": "3.0.0-beta.19.3"
|
"strapi-utils": "3.0.0-beta.19.3"
|
||||||
},
|
},
|
||||||
"strapi": {
|
"strapi": {
|
||||||
|
|||||||
@ -273,5 +273,6 @@
|
|||||||
"notification.contentType.relations.conflict": "Content type has conflicting relations",
|
"notification.contentType.relations.conflict": "Content type has conflicting relations",
|
||||||
"notification.form.error.fields": "The form contains some errors",
|
"notification.form.error.fields": "The form contains some errors",
|
||||||
"notification.form.success.fields": "Changes saved",
|
"notification.form.success.fields": "Changes saved",
|
||||||
|
"notification.success.delete": "The item has been deleted",
|
||||||
"global.prompt.unsaved": "Are you sure you want to leave this page? All your modifications will be lost"
|
"global.prompt.unsaved": "Are you sure you want to leave this page? All your modifications will be lost"
|
||||||
}
|
}
|
||||||
|
|||||||
@ -14,7 +14,14 @@ const Overlay = styled.div`
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 0;
|
left: 0;
|
||||||
background: linear-gradient(rgba(0, 0, 0, 15) 0%, rgba(0, 0, 0, 0) 100%);
|
${({ noGradient }) => {
|
||||||
|
if (noGradient) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `background: linear-gradient(rgba(0, 0, 0, 15) 0%, rgba(0, 0, 0, 0) 100%)`;
|
||||||
|
}};
|
||||||
|
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,7 +32,13 @@ const Overlay = styled.div`
|
|||||||
right: 0;
|
right: 0;
|
||||||
bottom: 0;
|
bottom: 0;
|
||||||
left: 24rem;
|
left: 24rem;
|
||||||
background: linear-gradient(#fbfbfb 20%, rgba(0, 0, 100, 0) 100%);
|
${({ noGradient }) => {
|
||||||
|
if (noGradient) {
|
||||||
|
return '';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `background: linear-gradient(#fbfbfb 20%, rgba(0, 0, 100, 0) 100%)`;
|
||||||
|
}};
|
||||||
box-shadow: inset 0px 2px 4px rgba(0, 0, 0, 0.1);
|
box-shadow: inset 0px 2px 4px rgba(0, 0, 0, 0.1);
|
||||||
box-shadow: inset 0 1px 2px 0 rgba(40, 42, 49, 0.16);
|
box-shadow: inset 0 1px 2px 0 rgba(40, 42, 49, 0.16);
|
||||||
}
|
}
|
||||||
@ -38,4 +51,9 @@ const Overlay = styled.div`
|
|||||||
z-index: 1100;
|
z-index: 1100;
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
|
Overlay.defaultProps = {
|
||||||
|
noGradient: false,
|
||||||
|
};
|
||||||
|
|
||||||
export default Overlay;
|
export default Overlay;
|
||||||
|
|||||||
@ -110,7 +110,7 @@ class OverlayBlocker extends React.Component {
|
|||||||
|
|
||||||
if (this.props.isOpen) {
|
if (this.props.isOpen) {
|
||||||
return ReactDOM.createPortal(
|
return ReactDOM.createPortal(
|
||||||
<Overlay>
|
<Overlay noGradient={this.props.noGradient}>
|
||||||
<div>{content}</div>
|
<div>{content}</div>
|
||||||
</Overlay>,
|
</Overlay>,
|
||||||
this.overlayContainer
|
this.overlayContainer
|
||||||
@ -126,6 +126,7 @@ OverlayBlocker.defaultProps = {
|
|||||||
description: 'components.OverlayBlocker.description',
|
description: 'components.OverlayBlocker.description',
|
||||||
icon: 'sync-alt',
|
icon: 'sync-alt',
|
||||||
isOpen: false,
|
isOpen: false,
|
||||||
|
noGradient: false,
|
||||||
title: 'components.OverlayBlocker.title',
|
title: 'components.OverlayBlocker.title',
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -134,6 +135,7 @@ OverlayBlocker.propTypes = {
|
|||||||
description: PropTypes.string,
|
description: PropTypes.string,
|
||||||
icon: PropTypes.string,
|
icon: PropTypes.string,
|
||||||
isOpen: PropTypes.bool,
|
isOpen: PropTypes.bool,
|
||||||
|
noGradient: PropTypes.bool,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -13,8 +13,8 @@ import Text from './Text';
|
|||||||
const MenuList = ({ selectProps: { changeMediaAllowedTypes, value }, ...rest }) => {
|
const MenuList = ({ selectProps: { changeMediaAllowedTypes, value }, ...rest }) => {
|
||||||
const { formatMessage } = useGlobalContext();
|
const { formatMessage } = useGlobalContext();
|
||||||
const Component = components.MenuList;
|
const Component = components.MenuList;
|
||||||
const areAllAllowedTypesSelected = value.value.length === 3;
|
const areAllAllowedTypesSelected = value.value && value.value.length === 3;
|
||||||
const someChecked = !areAllAllowedTypesSelected && value.value.length > 0;
|
const someChecked = value.value && !areAllAllowedTypesSelected && value.value.length > 0;
|
||||||
const options = [
|
const options = [
|
||||||
{
|
{
|
||||||
name: 'images',
|
name: 'images',
|
||||||
@ -58,7 +58,7 @@ const MenuList = ({ selectProps: { changeMediaAllowedTypes, value }, ...rest })
|
|||||||
</div>
|
</div>
|
||||||
<SubUl tad="ul" isOpen>
|
<SubUl tad="ul" isOpen>
|
||||||
{options.map(({ name, infos }) => {
|
{options.map(({ name, infos }) => {
|
||||||
const isChecked = value.value.includes(name);
|
const isChecked = value.value && value.value.includes(name);
|
||||||
const target = { name, value: !isChecked };
|
const target = { name, value: !isChecked };
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -15,8 +15,9 @@ const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) =>
|
|||||||
const ref = useRef();
|
const ref = useRef();
|
||||||
|
|
||||||
/* eslint-disable indent */
|
/* eslint-disable indent */
|
||||||
|
|
||||||
const displayedValue =
|
const displayedValue =
|
||||||
value.length === 0
|
value === null || value.length === 0
|
||||||
? formatMessage({ id: getTrad('form.attribute.media.allowed-types.none') })
|
? formatMessage({ id: getTrad('form.attribute.media.allowed-types.none') })
|
||||||
: value
|
: value
|
||||||
.sort()
|
.sort()
|
||||||
@ -35,16 +36,20 @@ const AllowedTypesSelect = ({ name, changeMediaAllowedTypes, styles, value }) =>
|
|||||||
ref={ref}
|
ref={ref}
|
||||||
refState={ref}
|
refState={ref}
|
||||||
styles={styles}
|
styles={styles}
|
||||||
value={{ label: displayedValue, value }}
|
value={{ label: displayedValue, value: value || '' }}
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
AllowedTypesSelect.defaultProps = {
|
||||||
|
value: null,
|
||||||
|
};
|
||||||
|
|
||||||
AllowedTypesSelect.propTypes = {
|
AllowedTypesSelect.propTypes = {
|
||||||
changeMediaAllowedTypes: PropTypes.func.isRequired,
|
changeMediaAllowedTypes: PropTypes.func.isRequired,
|
||||||
name: PropTypes.string.isRequired,
|
name: PropTypes.string.isRequired,
|
||||||
styles: PropTypes.object.isRequired,
|
styles: PropTypes.object.isRequired,
|
||||||
value: PropTypes.array.isRequired,
|
value: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
||||||
};
|
};
|
||||||
|
|
||||||
export default AllowedTypesSelect;
|
export default AllowedTypesSelect;
|
||||||
|
|||||||
@ -419,8 +419,8 @@ const DataManagerProvider = ({ allIcons, children }) => {
|
|||||||
if (!isInContentTypeView) {
|
if (!isInContentTypeView) {
|
||||||
emitEvent('didNotSaveComponent');
|
emitEvent('didNotSaveComponent');
|
||||||
}
|
}
|
||||||
console.error({ err });
|
console.error({ err: err.response });
|
||||||
strapi.notification.error(err.response.payload.error || 'notification.error');
|
strapi.notification.error('notification.error');
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -53,6 +53,7 @@ const FormModal = () => {
|
|||||||
const { emitEvent, formatMessage } = useGlobalContext();
|
const { emitEvent, formatMessage } = useGlobalContext();
|
||||||
const query = useQuery();
|
const query = useQuery();
|
||||||
const attributeOptionRef = useRef();
|
const attributeOptionRef = useRef();
|
||||||
|
|
||||||
const {
|
const {
|
||||||
addAttribute,
|
addAttribute,
|
||||||
addCreatedComponentToDynamicZone,
|
addCreatedComponentToDynamicZone,
|
||||||
@ -1197,6 +1198,8 @@ const FormModal = () => {
|
|||||||
value = retrievedValue.join('\n');
|
value = retrievedValue.join('\n');
|
||||||
} else if (input.name === 'uid') {
|
} else if (input.name === 'uid') {
|
||||||
value = input.value;
|
value = input.value;
|
||||||
|
} else if (input.name === 'allowedTypes' && retrievedValue === '') {
|
||||||
|
value = null;
|
||||||
} else {
|
} else {
|
||||||
value = retrievedValue;
|
value = retrievedValue;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -103,13 +103,21 @@ const reducer = (state, action) => {
|
|||||||
return fromJS(['images', 'videos', 'files']);
|
return fromJS(['images', 'videos', 'files']);
|
||||||
}
|
}
|
||||||
|
|
||||||
return fromJS([]);
|
return null;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
return state.updateIn(['modifiedData', 'allowedTypes'], list => {
|
return state.updateIn(['modifiedData', 'allowedTypes'], currentList => {
|
||||||
|
let list = currentList || fromJS([]);
|
||||||
|
|
||||||
if (list.includes(action.name)) {
|
if (list.includes(action.name)) {
|
||||||
return list.filter(v => v !== action.name);
|
list = list.filter(v => v !== action.name);
|
||||||
|
|
||||||
|
if (list.size === 0) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
return list.push(action.name);
|
return list.push(action.name);
|
||||||
|
|||||||
@ -248,7 +248,7 @@ describe('CTB | containers | FormModal | reducer | actions', () => {
|
|||||||
value: false,
|
value: false,
|
||||||
type: 'ON_CHANGE_ALLOWED_TYPE',
|
type: 'ON_CHANGE_ALLOWED_TYPE',
|
||||||
};
|
};
|
||||||
const expected = state.setIn(['modifiedData', 'allowedTypes'], fromJS([]));
|
const expected = state.setIn(['modifiedData', 'allowedTypes'], null);
|
||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expected);
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
});
|
});
|
||||||
@ -271,7 +271,7 @@ describe('CTB | containers | FormModal | reducer | actions', () => {
|
|||||||
expect(reducer(state, action)).toEqual(expected);
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('Shoul remove the type', () => {
|
it('Should remove the type', () => {
|
||||||
const state = initialState.setIn(
|
const state = initialState.setIn(
|
||||||
['modifiedData', 'allowedTypes'],
|
['modifiedData', 'allowedTypes'],
|
||||||
fromJS(['videos', 'images', 'files'])
|
fromJS(['videos', 'images', 'files'])
|
||||||
@ -285,6 +285,18 @@ describe('CTB | containers | FormModal | reducer | actions', () => {
|
|||||||
|
|
||||||
expect(reducer(state, action)).toEqual(expected);
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('Should remove set the allowedTypes to null if removing the last type', () => {
|
||||||
|
const state = initialState.setIn(['modifiedData', 'allowedTypes'], fromJS(['videos']));
|
||||||
|
const action = {
|
||||||
|
name: 'videos',
|
||||||
|
value: null,
|
||||||
|
type: 'ON_CHANGE_ALLOWED_TYPE',
|
||||||
|
};
|
||||||
|
const expected = state.setIn(['modifiedData', 'allowedTypes'], null);
|
||||||
|
|
||||||
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('RESET_PROPS', () => {
|
describe('RESET_PROPS', () => {
|
||||||
|
|||||||
@ -16,12 +16,7 @@ import { Inputs } from '@buffetjs/custom';
|
|||||||
import { useGlobalContext } from 'strapi-helper-plugin';
|
import { useGlobalContext } from 'strapi-helper-plugin';
|
||||||
import Cropper from 'cropperjs';
|
import Cropper from 'cropperjs';
|
||||||
import 'cropperjs/dist/cropper.css';
|
import 'cropperjs/dist/cropper.css';
|
||||||
import {
|
import { createFileToDownloadName, getTrad, prefixFileUrlWithBackendUrl } from '../../utils';
|
||||||
canDownloadFile,
|
|
||||||
createFileToDownloadName,
|
|
||||||
getTrad,
|
|
||||||
prefixFileUrlWithBackendUrl,
|
|
||||||
} from '../../utils';
|
|
||||||
import CardControl from '../CardControl';
|
import CardControl from '../CardControl';
|
||||||
import CardControlsWrapper from '../CardControlsWrapper';
|
import CardControlsWrapper from '../CardControlsWrapper';
|
||||||
import CardPreview from '../CardPreview';
|
import CardPreview from '../CardPreview';
|
||||||
@ -60,9 +55,9 @@ const EditForm = forwardRef(
|
|||||||
const [src, setSrc] = useState(null);
|
const [src, setSrc] = useState(null);
|
||||||
|
|
||||||
const fileURL = get(fileToEdit, ['file', 'url'], null);
|
const fileURL = get(fileToEdit, ['file', 'url'], null);
|
||||||
const isFileDownloadable = canDownloadFile(fileURL);
|
|
||||||
const prefixedFileURL = fileURL ? prefixFileUrlWithBackendUrl(fileURL) : null;
|
const prefixedFileURL = fileURL ? prefixFileUrlWithBackendUrl(fileURL) : null;
|
||||||
const downloadFileName = isFileDownloadable ? createFileToDownloadName(fileToEdit) : null;
|
const downloadFileName = createFileToDownloadName(fileToEdit);
|
||||||
const mimeType =
|
const mimeType =
|
||||||
get(fileToEdit, ['file', 'type'], null) || get(fileToEdit, ['file', 'mime'], '');
|
get(fileToEdit, ['file', 'type'], null) || get(fileToEdit, ['file', 'mime'], '');
|
||||||
const isImg = isImageType(mimeType);
|
const isImg = isImageType(mimeType);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Checkbox } from '@buffetjs/core';
|
import { Checkbox } from '@buffetjs/core';
|
||||||
|
import { get } from 'lodash';
|
||||||
import { createMatrix } from '../../utils';
|
import { createMatrix } from '../../utils';
|
||||||
import Card from '../Card';
|
import Card from '../Card';
|
||||||
import CardControlsWrapper from '../CardControlsWrapper';
|
import CardControlsWrapper from '../CardControlsWrapper';
|
||||||
@ -19,7 +20,8 @@ const List = ({ data, onChange, onClickEditFile, selectedItems, canSelect }) =>
|
|||||||
return (
|
return (
|
||||||
<div className="row" key={key}>
|
<div className="row" key={key}>
|
||||||
{rowContent.map(item => {
|
{rowContent.map(item => {
|
||||||
const { id, url } = item;
|
const { id } = item;
|
||||||
|
const url = get(item, ['formats', 'thumbnail', 'url'], '');
|
||||||
|
|
||||||
const checked = selectedItems.findIndex(file => file.id === id) !== -1;
|
const checked = selectedItems.findIndex(file => file.id === id) !== -1;
|
||||||
const fileUrl = url.startsWith('/') ? `${strapi.backendURL}${url}` : url;
|
const fileUrl = url.startsWith('/') ? `${strapi.backendURL}${url}` : url;
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import { Checkbox } from '@buffetjs/core';
|
import { Checkbox } from '@buffetjs/core';
|
||||||
|
import { get } from 'lodash';
|
||||||
import DraggableCard from './DraggableCard';
|
import DraggableCard from './DraggableCard';
|
||||||
import CardControlsWrapper from '../CardControlsWrapper';
|
import CardControlsWrapper from '../CardControlsWrapper';
|
||||||
import ListWrapper from '../ListWrapper';
|
import ListWrapper from '../ListWrapper';
|
||||||
@ -14,7 +15,8 @@ const SortableList = ({ data, moveAsset, onChange, onClickEditFile, selectedItem
|
|||||||
<ListWrapper>
|
<ListWrapper>
|
||||||
<div className="row">
|
<div className="row">
|
||||||
{data.map((item, index) => {
|
{data.map((item, index) => {
|
||||||
const { id, url } = item;
|
const { id } = item;
|
||||||
|
const url = get(item, ['formats', 'thumbnail', 'url'], '');
|
||||||
const checked = selectedItems.findIndex(file => file.id === id) !== -1;
|
const checked = selectedItems.findIndex(file => file.id === id) !== -1;
|
||||||
const fileUrl = url.startsWith('/') ? `${strapi.backendURL}${url}` : url;
|
const fileUrl = url.startsWith('/') ? `${strapi.backendURL}${url}` : url;
|
||||||
|
|
||||||
|
|||||||
@ -71,6 +71,7 @@ const HomePage = () => {
|
|||||||
await request(requestURL, {
|
await request(requestURL, {
|
||||||
method: 'DELETE',
|
method: 'DELETE',
|
||||||
});
|
});
|
||||||
|
strapi.notification.success('notification.success.delete');
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
strapi.notification.error('notification.error');
|
strapi.notification.error('notification.error');
|
||||||
@ -79,6 +80,8 @@ const HomePage = () => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const fetchListData = async () => {
|
const fetchListData = async () => {
|
||||||
|
dispatch({ type: 'GET_DATA' });
|
||||||
|
|
||||||
const [data, count] = await Promise.all([fetchData(), fetchDataCount()]);
|
const [data, count] = await Promise.all([fetchData(), fetchDataCount()]);
|
||||||
|
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
@ -101,8 +104,11 @@ const HomePage = () => {
|
|||||||
|
|
||||||
return Promise.resolve(data);
|
return Promise.resolve(data);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
|
if (isMounted) {
|
||||||
|
dispatch({ type: 'GET_DATA_ERROR' });
|
||||||
strapi.notification.error('notification.error');
|
strapi.notification.error('notification.error');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [];
|
return [];
|
||||||
};
|
};
|
||||||
@ -118,6 +124,7 @@ const HomePage = () => {
|
|||||||
return Promise.resolve(count);
|
return Promise.resolve(count);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
if (isMounted) {
|
if (isMounted) {
|
||||||
|
dispatch({ type: 'GET_DATA_ERROR' });
|
||||||
strapi.notification.error('notification.error');
|
strapi.notification.error('notification.error');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -204,6 +211,28 @@ const HomePage = () => {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleDeleteMediaFromModal = async id => {
|
||||||
|
handleClickToggleModal();
|
||||||
|
const overlayblockerParams = {
|
||||||
|
children: <div />,
|
||||||
|
noGradient: true,
|
||||||
|
};
|
||||||
|
strapi.lockApp(overlayblockerParams);
|
||||||
|
|
||||||
|
try {
|
||||||
|
await deleteMedia(id);
|
||||||
|
|
||||||
|
dispatch({
|
||||||
|
type: 'ON_DELETE_MEDIA_SUCCEEDED',
|
||||||
|
mediaId: id,
|
||||||
|
});
|
||||||
|
} catch (err) {
|
||||||
|
// Silent
|
||||||
|
} finally {
|
||||||
|
strapi.unlockApp();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const handleDeleteMedias = async () => {
|
const handleDeleteMedias = async () => {
|
||||||
await Promise.all(dataToDelete.map(item => deleteMedia(item.id)));
|
await Promise.all(dataToDelete.map(item => deleteMedia(item.id)));
|
||||||
|
|
||||||
@ -333,7 +362,9 @@ const HomePage = () => {
|
|||||||
initialStep={modalInitialStep}
|
initialStep={modalInitialStep}
|
||||||
isOpen={isModalOpen}
|
isOpen={isModalOpen}
|
||||||
onClosed={handleModalClose}
|
onClosed={handleModalClose}
|
||||||
|
onDeleteMedia={handleDeleteMediaFromModal}
|
||||||
onToggle={handleClickToggleModal}
|
onToggle={handleClickToggleModal}
|
||||||
|
refetchData={fetchListData}
|
||||||
/>
|
/>
|
||||||
<PopUpWarning
|
<PopUpWarning
|
||||||
isOpen={isPopupOpen}
|
isOpen={isPopupOpen}
|
||||||
|
|||||||
@ -11,6 +11,10 @@ const reducer = (state, action) => {
|
|||||||
switch (action.type) {
|
switch (action.type) {
|
||||||
case 'CLEAR_DATA_TO_DELETE':
|
case 'CLEAR_DATA_TO_DELETE':
|
||||||
return state.update('dataToDelete', () => fromJS([]));
|
return state.update('dataToDelete', () => fromJS([]));
|
||||||
|
case 'GET_DATA':
|
||||||
|
return state.update('isLoading', () => true);
|
||||||
|
case 'GET_DATA_ERROR':
|
||||||
|
return state.update('isLoading', () => false);
|
||||||
case 'GET_DATA_SUCCEEDED':
|
case 'GET_DATA_SUCCEEDED':
|
||||||
return state
|
return state
|
||||||
.update('data', () => fromJS(action.data))
|
.update('data', () => fromJS(action.data))
|
||||||
@ -48,6 +52,10 @@ const reducer = (state, action) => {
|
|||||||
return dataToDelete.concat(newItems);
|
return dataToDelete.concat(newItems);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
case 'ON_DELETE_MEDIA_SUCCEEDED':
|
||||||
|
return state
|
||||||
|
.update('data', list => list.filter(item => item.get('id') !== action.mediaId))
|
||||||
|
.update('dataCount', count => count - 1);
|
||||||
default:
|
default:
|
||||||
return state;
|
return state;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,6 +2,44 @@ import { fromJS } from 'immutable';
|
|||||||
import reducer, { initialState } from '../reducer';
|
import reducer, { initialState } from '../reducer';
|
||||||
|
|
||||||
describe('Upload | containers | HomePage | reducer', () => {
|
describe('Upload | containers | HomePage | reducer', () => {
|
||||||
|
describe('GET_DATA', () => {
|
||||||
|
it('should set isLoading to true', () => {
|
||||||
|
const state = fromJS({
|
||||||
|
isLoading: false,
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
const action = {
|
||||||
|
type: 'GET_DATA',
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = fromJS({
|
||||||
|
isLoading: true,
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('GET_DATA_ERROR', () => {
|
||||||
|
it('should set isLoading to false', () => {
|
||||||
|
const state = fromJS({
|
||||||
|
isLoading: true,
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
const action = {
|
||||||
|
type: 'GET_DATA_ERROR',
|
||||||
|
};
|
||||||
|
|
||||||
|
const expected = fromJS({
|
||||||
|
isLoading: false,
|
||||||
|
test: true,
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(reducer(state, action)).toEqual(expected);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
it('should update data with received data', () => {
|
it('should update data with received data', () => {
|
||||||
const state = initialState;
|
const state = initialState;
|
||||||
|
|
||||||
|
|||||||
@ -4,13 +4,20 @@ import { get } from 'lodash';
|
|||||||
import { Modal, ModalFooter, PopUpWarning, useGlobalContext, request } from 'strapi-helper-plugin';
|
import { Modal, ModalFooter, PopUpWarning, useGlobalContext, request } from 'strapi-helper-plugin';
|
||||||
import { Button } from '@buffetjs/core';
|
import { Button } from '@buffetjs/core';
|
||||||
import pluginId from '../../pluginId';
|
import pluginId from '../../pluginId';
|
||||||
import { getRequestUrl, getTrad } from '../../utils';
|
import { getTrad } from '../../utils';
|
||||||
import ModalHeader from '../../components/ModalHeader';
|
import ModalHeader from '../../components/ModalHeader';
|
||||||
import stepper from './stepper';
|
import stepper from './stepper';
|
||||||
import init from './init';
|
import init from './init';
|
||||||
import reducer, { initialState } from './reducer';
|
import reducer, { initialState } from './reducer';
|
||||||
|
|
||||||
const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onToggle }) => {
|
const ModalStepper = ({
|
||||||
|
initialFileToEdit,
|
||||||
|
initialStep,
|
||||||
|
isOpen,
|
||||||
|
onClosed,
|
||||||
|
onDeleteMedia,
|
||||||
|
onToggle,
|
||||||
|
}) => {
|
||||||
const { formatMessage } = useGlobalContext();
|
const { formatMessage } = useGlobalContext();
|
||||||
const [isWarningDeleteOpen, setIsWarningDeleteOpen] = useState(false);
|
const [isWarningDeleteOpen, setIsWarningDeleteOpen] = useState(false);
|
||||||
const [shouldDeleteFile, setShouldDeleteFile] = useState(false);
|
const [shouldDeleteFile, setShouldDeleteFile] = useState(false);
|
||||||
@ -66,15 +73,15 @@ const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onTogg
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleCancelFileToUpload = fileIndex => {
|
const handleCancelFileToUpload = fileOriginalIndex => {
|
||||||
const fileToCancel = get(filesToUpload, fileIndex, {});
|
const fileToCancel = filesToUpload.find(file => file.originalIndex === fileOriginalIndex);
|
||||||
|
|
||||||
// Cancel upload
|
// Cancel upload
|
||||||
fileToCancel.abortController.abort();
|
fileToCancel.abortController.abort();
|
||||||
|
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'REMOVE_FILE_TO_UPLOAD',
|
type: 'REMOVE_FILE_TO_UPLOAD',
|
||||||
fileIndex,
|
fileIndex: fileOriginalIndex,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -123,16 +130,7 @@ const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onTogg
|
|||||||
if (shouldDeleteFile) {
|
if (shouldDeleteFile) {
|
||||||
const { id } = fileToEdit;
|
const { id } = fileToEdit;
|
||||||
|
|
||||||
try {
|
onDeleteMedia(id);
|
||||||
const requestURL = getRequestUrl(`files/${id}`);
|
|
||||||
|
|
||||||
await request(requestURL, { method: 'DELETE' });
|
|
||||||
|
|
||||||
setShouldDeleteFile(false);
|
|
||||||
toggleRef.current(true);
|
|
||||||
} catch (err) {
|
|
||||||
console.log(err);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -268,6 +266,7 @@ const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onTogg
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
if (errorMessage) {
|
||||||
dispatch({
|
dispatch({
|
||||||
type: 'SET_FILE_ERROR',
|
type: 'SET_FILE_ERROR',
|
||||||
fileIndex: originalIndex,
|
fileIndex: originalIndex,
|
||||||
@ -275,6 +274,7 @@ const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onTogg
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
await Promise.all(requests);
|
await Promise.all(requests);
|
||||||
@ -330,12 +330,12 @@ const ModalStepper = ({ initialFileToEdit, initialStep, isOpen, onClosed, onTogg
|
|||||||
onChange={handleChange}
|
onChange={handleChange}
|
||||||
onClickCancelUpload={handleCancelFileToUpload}
|
onClickCancelUpload={handleCancelFileToUpload}
|
||||||
onClickDeleteFileToUpload={
|
onClickDeleteFileToUpload={
|
||||||
currentStep === 'edit-new' ? handleClickDeleteFileToUpload : handleClickDeleteFile
|
currentStep === 'edit' ? handleClickDeleteFile : handleClickDeleteFileToUpload
|
||||||
}
|
}
|
||||||
onClickEditNewFile={handleGoToEditNewFile}
|
onClickEditNewFile={handleGoToEditNewFile}
|
||||||
onGoToAddBrowseFiles={handleGoToAddBrowseFiles}
|
onGoToAddBrowseFiles={handleGoToAddBrowseFiles}
|
||||||
onSubmitEdit={
|
onSubmitEdit={
|
||||||
currentStep === 'edit-new' ? handleSubmitEditNewFile : handleSubmitEditExistingFile
|
currentStep === 'edit' ? handleSubmitEditExistingFile : handleSubmitEditNewFile
|
||||||
}
|
}
|
||||||
onToggle={handleToggle}
|
onToggle={handleToggle}
|
||||||
toggleDisableForm={setIsFormDisabled}
|
toggleDisableForm={setIsFormDisabled}
|
||||||
@ -408,6 +408,7 @@ ModalStepper.defaultProps = {
|
|||||||
initialFileToEdit: null,
|
initialFileToEdit: null,
|
||||||
initialStep: 'browse',
|
initialStep: 'browse',
|
||||||
onClosed: () => {},
|
onClosed: () => {},
|
||||||
|
onDeleteMedia: () => {},
|
||||||
onToggle: () => {},
|
onToggle: () => {},
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -416,6 +417,7 @@ ModalStepper.propTypes = {
|
|||||||
initialStep: PropTypes.string,
|
initialStep: PropTypes.string,
|
||||||
isOpen: PropTypes.bool.isRequired,
|
isOpen: PropTypes.bool.isRequired,
|
||||||
onClosed: PropTypes.func,
|
onClosed: PropTypes.func,
|
||||||
|
onDeleteMedia: PropTypes.func,
|
||||||
onToggle: PropTypes.func,
|
onToggle: PropTypes.func,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -7,7 +7,7 @@ const formatFileForEditing = file => {
|
|||||||
abortController,
|
abortController,
|
||||||
id: file.id,
|
id: file.id,
|
||||||
file: {
|
file: {
|
||||||
...pick(file, ['size', 'ext', 'width', 'height', 'url', 'mime', 'name']),
|
...pick(file, ['size', 'ext', 'width', 'height', 'mime', 'name', 'url']),
|
||||||
created_at: file.created_at || file.createdAt,
|
created_at: file.created_at || file.createdAt,
|
||||||
},
|
},
|
||||||
fileInfo: pick(file, ['alternativeText', 'caption', 'name']),
|
fileInfo: pick(file, ['alternativeText', 'caption', 'name']),
|
||||||
|
|||||||
@ -19,8 +19,18 @@ describe('UPLOAD | utils | formatFileForEditing', () => {
|
|||||||
updated_at: '2020-03-23T11:43:46.729Z',
|
updated_at: '2020-03-23T11:43:46.729Z',
|
||||||
alternativeText: 'test',
|
alternativeText: 'test',
|
||||||
id: 12,
|
id: 12,
|
||||||
formats: null,
|
|
||||||
provider_metadata: null,
|
provider_metadata: null,
|
||||||
|
formats: {
|
||||||
|
thumbnail: {
|
||||||
|
hash: 'thumbnail_Screenshot_2020-03-26_at_13.09.24.png_df7f56f901',
|
||||||
|
ext: '.png',
|
||||||
|
mime: 'image/png',
|
||||||
|
width: 245,
|
||||||
|
height: 23,
|
||||||
|
size: 4.09,
|
||||||
|
url: '/uploads/thumbnail_Screenshot_2020-03-26_at_13.09.24.png_df7f56f901.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
|
|
||||||
@ -68,7 +78,17 @@ describe('UPLOAD | utils | formatFileForEditing', () => {
|
|||||||
updated_at: '2020-03-23T11:43:46.729Z',
|
updated_at: '2020-03-23T11:43:46.729Z',
|
||||||
alternativeText: 'test',
|
alternativeText: 'test',
|
||||||
id: 12,
|
id: 12,
|
||||||
formats: null,
|
formats: {
|
||||||
|
thumbnail: {
|
||||||
|
hash: 'thumbnail_Screenshot_2020-03-26_at_13.09.24.png_df7f56f901',
|
||||||
|
ext: '.png',
|
||||||
|
mime: 'image/png',
|
||||||
|
width: 245,
|
||||||
|
height: 23,
|
||||||
|
size: 4.09,
|
||||||
|
url: '/uploads/thumbnail_Screenshot_2020-03-26_at_13.09.24.png_df7f56f901.png',
|
||||||
|
},
|
||||||
|
},
|
||||||
provider_metadata: null,
|
provider_metadata: null,
|
||||||
};
|
};
|
||||||
const abortController = new AbortController();
|
const abortController = new AbortController();
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user