Merge branch 'master' into features/sentry-plugin

This commit is contained in:
Alexandre Bodin 2021-02-01 18:32:25 +01:00
commit aa806d1a79
16 changed files with 300 additions and 96 deletions

View File

@ -13,7 +13,7 @@
"lib": "./lib"
},
"dependencies": {
"@sentry/node": "^5.27.3",
"@sentry/node": "6.0.3",
"chalk": "^2.4.2",
"execa": "^1.0.0",
"fs-extra": "^9.0.1",

View File

@ -1,7 +1,7 @@
import styled from 'styled-components';
const Container = styled.div`
padding: 18px 30px 18px 30px;
padding: 18px 30px 66px 30px;
`;
export default Container;

View File

@ -42,6 +42,7 @@ const InputUID = ({
contentTypeUID,
description,
error: inputError,
label: inputLabel,
name,
onChange,
validations,
@ -217,7 +218,7 @@ const InputUID = ({
return (
<Wrapper ref={wrapperRef}>
<Name htmlFor={name}>{name}</Name>
<Name htmlFor={name}>{inputLabel}</Name>
<InputContainer>
<Input
{...inputProps}
@ -291,6 +292,7 @@ InputUID.propTypes = {
description: PropTypes.string,
editable: PropTypes.bool,
error: PropTypes.string,
label: PropTypes.string.isRequired,
name: PropTypes.string.isRequired,
onChange: PropTypes.func.isRequired,
validations: PropTypes.object,

View File

@ -16,7 +16,7 @@
"apollo-server-koa": "2.19.1",
"dataloader": "^1.4.0",
"glob": "^7.1.6",
"graphql": "15.4.0",
"graphql": "15.5.0",
"graphql-depth-limit": "^1.1.0",
"graphql-iso-date": "^3.6.1",
"graphql-playground-middleware-koa": "^1.6.21",

View File

@ -40,11 +40,11 @@ const List = ({
<ListRow>
{data.map(item => {
const { id } = item;
const url = get(item, ['formats', 'small', 'url'], item.url);
const thumbnail = get(item, ['formats', 'small'], item);
const isAllowed =
allowedTypes.length > 0 ? allowedTypes.includes(getType(item.mime)) : true;
const checked = selectedItems.findIndex(file => file.id === id) !== -1;
const fileUrl = prefixFileUrlWithBackendUrl(url);
const fileUrl = prefixFileUrlWithBackendUrl(thumbnail.url);
return (
<ListCell key={id}>
@ -53,6 +53,7 @@ const List = ({
checked={checked}
{...item}
url={fileUrl}
mime={thumbnail.mime}
onClick={onCardClick}
small={smallCards}
>

View File

@ -1,18 +1,36 @@
import React, { useEffect, useReducer, useRef } from 'react';
import PropTypes from 'prop-types';
import styled from 'styled-components';
import { FormattedMessage, useIntl } from 'react-intl';
import Duration from '../Duration';
import LoadingIndicator from '../LoadingIndicator';
import PlayIcon from '../PlayIcon';
import Wrapper from './Wrapper';
import CanvasWrapper from './CanvasWrapper';
import Thumbnail from './Thumbnail';
import reducer, { initialState } from './reducer';
import getTrad from '../../utils/getTrad';
const EmptyPreview = styled.div`
display: flex;
align-items: center;
justify-content: center;
font-size: ${({ theme }) => theme.main.sizes.fonts.xs};
color: ${({ theme }) => theme.main.colors.grey};
`;
const VideoPreview = ({ hasIcon, previewUrl, src }) => {
const { formatMessage } = useIntl();
const [reducerState, dispatch] = useReducer(reducer, initialState);
const { duration, dataLoaded, isHover, metadataLoaded, snapshot, seeked } = reducerState.toJS();
const {
duration,
dataLoaded,
isHover,
metadataLoaded,
snapshot,
seeked,
isError,
} = reducerState.toJS();
// Adapted from https://github.com/brothatru/react-video-thumbnail/blob/master/src/components/VideoThumbnail.js
// And from https://github.com/soupette/poc-video-preview
@ -51,6 +69,14 @@ const VideoPreview = ({ hasIcon, previewUrl, src }) => {
}
}, [dataLoaded, metadataLoaded, seeked, snapshot]);
if (isError) {
return (
<EmptyPreview>
<FormattedMessage id={getTrad('list.assets.not-supported-content')} />
</EmptyPreview>
);
}
return (
<Wrapper
// Specify isHover to prevent bad behavior when compo is under the cursor on modal open
@ -67,17 +93,35 @@ const VideoPreview = ({ hasIcon, previewUrl, src }) => {
});
}}
>
{!snapshot && <LoadingIndicator />}
{!snapshot && (
<LoadingIndicator
aria-label={formatMessage(
{
id: getTrad('list.assets.loading-asset'),
},
{ path: src }
)}
/>
)}
<CanvasWrapper>
{previewUrl ? (
<Thumbnail src={previewUrl} />
<Thumbnail
src={previewUrl}
alt={formatMessage(
{
id: getTrad('list.assets.preview-asset'),
},
{ path: src }
)}
/>
) : (
<>
<video
muted
ref={videoRef}
src={src}
crossOrigin="anonymous"
onError={() => dispatch({ type: 'SET_ERROR', isError: true })}
onLoadedMetadata={() => {
dispatch({
type: 'METADATA_LOADED',
@ -99,6 +143,7 @@ const VideoPreview = ({ hasIcon, previewUrl, src }) => {
</>
)}
<Duration duration={duration} />
{(hasIcon || isHover) && <PlayIcon small />}
</CanvasWrapper>
</Wrapper>

View File

@ -7,6 +7,7 @@ const initialState = fromJS({
metadataLoaded: false,
seeked: false,
snapshot: false,
isError: false,
});
const videoReducer = (state, action) => {
@ -21,6 +22,8 @@ const videoReducer = (state, action) => {
return state.update('isHover', () => action.isHover);
case 'SET_SNAPSHOT':
return state.update('snapshot', () => action.snapshot);
case 'SET_ERROR':
return state.update('isError', () => action.isError);
default:
return state;
}

View File

@ -0,0 +1,77 @@
import React from 'react';
import { screen, render, fireEvent } from '@testing-library/react';
import { ThemeProvider } from 'styled-components';
import VideoPreview from '..';
import themes from '../../../../../../strapi-admin/admin/src/themes';
jest.mock('react-intl', () => ({
// eslint-disable-next-line react/prop-types
FormattedMessage: ({ id }) => <div>{id}</div>,
useIntl: () => ({
formatMessage: ({ id }) => id,
}),
}));
describe('VideoPreview', () => {
it('shows its initial state with no props', () => {
const { container } = render(
<ThemeProvider theme={themes}>
<VideoPreview />
</ThemeProvider>
);
expect(container).toMatchSnapshot();
});
it('shows a loading state when resolving the asset', () => {
render(
<ThemeProvider theme={themes}>
<VideoPreview
hasIcon
previewUrl="https://some-preview-url/img.jpg"
src="https://something-good/video.mp4"
/>
</ThemeProvider>
);
expect(screen.getByLabelText('upload.list.assets.loading-asset')).toBeVisible();
});
it('shows the thumbnail but not the video when previewURL is passed', () => {
const { container } = render(
<ThemeProvider theme={themes}>
<VideoPreview
hasIcon
previewUrl="https://some-preview-url/img.jpg"
src="https://something-good/video.mp4"
/>
</ThemeProvider>
);
expect(screen.getByAltText('upload.list.assets.preview-asset')).toBeVisible();
expect(container.querySelector('video')).toBeFalsy();
});
it('shows the video when the previewURL is not passed', () => {
const { container } = render(
<ThemeProvider theme={themes}>
<VideoPreview hasIcon src="https://something-good/video.mp4" />
</ThemeProvider>
);
expect(container.querySelector('video')).toBeVisible();
});
it('shows a fallback message when the video is in error', () => {
const { container } = render(
<ThemeProvider theme={themes}>
<VideoPreview hasIcon src="https://something-good/video.wvf" />
</ThemeProvider>
);
fireEvent(container.querySelector('video'), new Event('error'));
expect(screen.getByText('upload.list.assets.not-supported-content')).toBeVisible();
});
});

View File

@ -0,0 +1,118 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`VideoPreview shows its initial state with no props 1`] = `
.c3 {
margin: 0;
line-height: normal;
color: #ffffff;
font-size: 13px;
font-weight: 500;
text-transform: none;
}
.c4 {
position: absolute;
bottom: 10px;
right: 10px;
padding: 3px 5px;
border-radius: 2px;
background-color: #333740;
}
.c1 {
position: relative;
width: 44%;
height: 4px;
overflow: hidden;
background-color: #515764;
border-radius: 2px;
}
.c1:before {
content: '';
display: block;
position: absolute;
left: -100px;
width: 100px;
height: 4px;
background-color: #b3b5b9;
-webkit-animation: gPeyzP 2s linear infinite;
animation: gPeyzP 2s linear infinite;
}
.c0 {
position: relative;
width: 100%;
height: 100%;
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
}
.c0 video {
display: none;
}
.c2 {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex;
-webkit-box-pack: center;
-webkit-justify-content: center;
-ms-flex-pack: center;
justify-content: center;
-webkit-align-items: center;
-webkit-box-align: center;
-ms-flex-align: center;
align-items: center;
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
.c2 canvas {
display: block;
max-width: 100%;
max-height: 100%;
width: auto;
height: auto;
margin: auto;
}
<div>
<div
class="c0"
>
<div
aria-label="upload.list.assets.loading-asset"
class="c1"
/>
<div
class="c2"
>
<video />
<canvas />
<p
class="c3 c4"
color="white"
font-size="md"
font-weight="semiBold"
>
00:00
</p>
</div>
</div>
</div>
`;

View File

@ -79,4 +79,17 @@ describe('Upload | components | VideoPreview | reducer', () => {
expect(reducer(state, action)).toEqual(expectedState);
});
it('should set isError to true when the payload is true', () => {
const state = initialState;
const action = {
type: 'SET_ERROR',
isError: true,
};
const expectedState = state.set('isError', true);
expect(reducer(state, action)).toEqual(expectedState);
});
});

View File

@ -35,6 +35,9 @@
"list.assets.selected.plural": "{number} assets selected",
"list.assets.selected.singular": "{number} asset selected",
"list.assets.type-not-allowed": "This type of file is not allowed.",
"list.assets.not-supported-content": "No preview available",
"list.assets.loading-asset": "Loading the preview for the media: {path}",
"list.assets.preview-asset": "Preview for the video at path {path}",
"modal.file-details.date": "Date",
"modal.file-details.dimensions": "Dimensions",
"modal.file-details.extension": "Extension",

View File

@ -35,6 +35,9 @@
"list.assets.selected.plural": "{number} médias sélectionnés",
"list.assets.selected.singular": "{number} média sélectionné",
"list.assets.type-not-allowed": "Ce type de fichier n'est pas autorisé.",
"list.assets.not-supported-content": "Preview non disponible",
"list.assets.loading-asset": "Chargement du contenu pour le media {path}",
"list.assets.preview-asset": "Preview de la vidéo {path}",
"modal.file-details.date": "Date",
"modal.file-details.dimensions": "Dimensions",
"modal.file-details.extension": "Extension",

View File

@ -4,6 +4,7 @@ import en from './en.json';
import es from './es.json';
import fr from './fr.json';
import he from './he.json';
import it from './it.json';
import ja from './ja.json';
import ms from './ms.json';
import ru from './ru.json';
@ -20,6 +21,7 @@ const trads = {
es,
fr,
he,
it,
ja,
ms,
ru,

View File

@ -111,8 +111,16 @@ const hasDeepFilters = ({ where = [], sort = [] }, { minDepth = 1 } = {}) => {
const normalizeWhereClauses = (whereClauses, { model }) => {
return whereClauses
.filter(({ value }) => !_.isNil(value))
.filter(({ value }) => !_.isNull(value))
.map(({ field, operator, value }) => {
if (_.isUndefined(value)) {
const err = new Error(
`The value of field: '${field}', in your where filter, is undefined.`
);
err.status = 400;
throw err;
}
if (BOOLEAN_OPERATORS.includes(operator)) {
return {
field,

View File

@ -7,6 +7,8 @@
// Setup the strapi functioon global variable
import '@testing-library/jest-dom/extend-expect';
const React = require('react');
const hoistNonReactStatics = require('hoist-non-react-statics');

View File

@ -2694,17 +2694,6 @@
"@sendgrid/client" "^6.4.0"
"@sendgrid/helpers" "^6.4.0"
"@sentry/core@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-5.27.3.tgz#d7a175b71596b7eb4b2e8b4cd1858a60d95813bb"
integrity sha512-yqepQO88jSt5hy0awpk61AxI4oHB09LjVbUEk4nJDg+1YXuND23cuZvH+Sp2jCZX2vrsw2tefwflToYfA8/U2w==
dependencies:
"@sentry/hub" "5.27.3"
"@sentry/minimal" "5.27.3"
"@sentry/types" "5.27.3"
"@sentry/utils" "5.27.3"
tslib "^1.9.3"
"@sentry/core@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/core/-/core-6.0.3.tgz#620cb32365a11eac75497bed281bd52b9f0bb359"
@ -2716,15 +2705,6 @@
"@sentry/utils" "6.0.3"
tslib "^1.9.3"
"@sentry/hub@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-5.27.3.tgz#f509c2fd38f500afef6030504e82510dbd0649d6"
integrity sha512-icEH3hr6NVQkpowXZcPOs9IgJZP5lMKtvud4mVioSpkd+NxtRdKrGEX4eF2TCviOJc9Md0mV4K+aL5Au7hxggQ==
dependencies:
"@sentry/types" "5.27.3"
"@sentry/utils" "5.27.3"
tslib "^1.9.3"
"@sentry/hub@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/hub/-/hub-6.0.3.tgz#097f7b1e775a4c6c20c9bec60d7507d5ad2e8db0"
@ -2734,15 +2714,6 @@
"@sentry/utils" "6.0.3"
tslib "^1.9.3"
"@sentry/minimal@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-5.27.3.tgz#c9263bdd6270bfeae64137177448911dff568e53"
integrity sha512-ng01cM0rsE1RMjqVTpPLN0ZVkTo0I675usM1krkpQe8ddW6tfQ6EJWpt02/BrpQZRQzTtfWp6/RyB1KFXg6icg==
dependencies:
"@sentry/hub" "5.27.3"
"@sentry/types" "5.27.3"
tslib "^1.9.3"
"@sentry/minimal@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/minimal/-/minimal-6.0.3.tgz#6eaaf78c479c49720df3e712d41518e7f4f0ffdf"
@ -2767,32 +2738,6 @@
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/node@^5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/node/-/node-5.27.3.tgz#174b81fbca8cadac12afe49910cbe9cc25b23f87"
integrity sha512-IZ/TkYRY+P/E5C+RF6Rcb6tpY59fyk0040Q3akzbDjb/hrw5TRKnK8fJ6/0gXCAOvlDPIlpRHFJgJ1p2QgWy+g==
dependencies:
"@sentry/core" "5.27.3"
"@sentry/hub" "5.27.3"
"@sentry/tracing" "5.27.3"
"@sentry/types" "5.27.3"
"@sentry/utils" "5.27.3"
cookie "^0.4.1"
https-proxy-agent "^5.0.0"
lru_map "^0.3.3"
tslib "^1.9.3"
"@sentry/tracing@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-5.27.3.tgz#787e57a2f7071e375f4fad0f3c3a5ff3381928e7"
integrity sha512-UWrHMdGxPfx1u558CWm1tptc2z0BuqCHVe2+BNN7POahq5BkpbGqaotyPQTBHbfmcs6QGfsMG57ou8HQFrBxyA==
dependencies:
"@sentry/hub" "5.27.3"
"@sentry/minimal" "5.27.3"
"@sentry/types" "5.27.3"
"@sentry/utils" "5.27.3"
tslib "^1.9.3"
"@sentry/tracing@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/tracing/-/tracing-6.0.3.tgz#103f4942ddd546321e22ba20c011adf52b25b3f2"
@ -2804,24 +2749,11 @@
"@sentry/utils" "6.0.3"
tslib "^1.9.3"
"@sentry/types@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-5.27.3.tgz#d377508769bc658d672c287166c7f6c5db45660c"
integrity sha512-PkWhMArFMxBb1g3HtMEL8Ea9PYae2MU0z9CMIWiqzerFy2ZpKG98IU3pt8ic4JkmKQdwB8hDiZpRPMHhW0WYwQ==
"@sentry/types@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/types/-/types-6.0.3.tgz#a1ef6d6b2ac2a9201e3e4a894db6ecf7ceb5b27c"
integrity sha512-266aBQbk9AGedhG2dzXshWbn23LYLElXqlI74DLku48UrU2v7TGKdyik/8/nfOfquCoRSp0GFGYHbItwU124XQ==
"@sentry/utils@5.27.3":
version "5.27.3"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-5.27.3.tgz#1fc45dfad1f1e4398bee58684d8947666d8d3003"
integrity sha512-R9WvFrRBALZvCzu/9BsuXBCfkNxz4MwdBNSXaBsJo4afQw1ljkjIc9DpHzlL9S9goIwXo81Buwmr5gGDO6aH+Q==
dependencies:
"@sentry/types" "5.27.3"
tslib "^1.9.3"
"@sentry/utils@6.0.3":
version "6.0.3"
resolved "https://registry.yarnpkg.com/@sentry/utils/-/utils-6.0.3.tgz#114d9faa47f76416c3e140711465e76d2129dba8"
@ -9384,10 +9316,10 @@ graphql-upload@^8.0.2:
http-errors "^1.7.3"
object-path "^0.11.4"
graphql@15.4.0, graphql@^15.3.0:
version "15.4.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.4.0.tgz#e459dea1150da5a106486ba7276518b5295a4347"
integrity sha512-EB3zgGchcabbsU9cFe1j+yxdzKQKAbGUWRb13DsrsMN1yyfmmIq+2+L5MqVWcDCE4V89R5AyUOi7sMOGxdsYtA==
graphql@15.5.0, graphql@^15.3.0:
version "15.5.0"
resolved "https://registry.yarnpkg.com/graphql/-/graphql-15.5.0.tgz#39d19494dbe69d1ea719915b578bf920344a69d5"
integrity sha512-OmaM7y0kaK31NKG31q4YbD2beNYa6jBBKtMFT6gLYJljHLJr42IqJ8KX08u3Li/0ifzTU5HjmoOOrwa5BRLeDA==
growl@1.9.2:
version "1.9.2"
@ -19304,21 +19236,16 @@ tslib@^1, tslib@^1.10.0, tslib@^1.11.2, tslib@^1.13.0, tslib@^1.9.0, tslib@^1.9.
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.13.0.tgz#c881e13cc7015894ed914862d276436fa9a47043"
integrity sha512-i/6DQjL8Xf3be4K/E6Wgpekn5Qasl1usyw++dAA35Ue5orEn65VIxOA+YvNNl9HV3qv70T7CNwjODHZrLwvd1Q==
tslib@^2.0.0, tslib@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.1.tgz#410eb0d113e5b6356490eec749603725b021b43e"
integrity sha512-SgIkNheinmEBgx1IUNirK0TUD4X9yjjBRTqqjggWCU3pUEqIk3/Uwl3yRixYKT6WjQuGiwDv4NomL3wqRCj+CQ==
tslib@^2.0.3, tslib@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
tslib@~2.1.0:
tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.1.0.tgz#da60860f1c2ecaa5703ab7d39bc05b6bf988b97a"
integrity sha512-hcVC3wYEziELGGmEEXue7D75zbwIIVUMWAVbHItGPx0ziyXxrOMQx4rQEVEV45Ut/1IotuEvwqPopzIOkDMf0A==
tslib@~2.0.1:
version "2.0.3"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.0.3.tgz#8e0741ac45fc0c226e58a17bfc3e64b9bc6ca61c"
integrity sha512-uZtkfKblCEQtZKBF6EBXVZeQNl82yqtDQdv+eck8u7tdPxjLu2/lp5/uPW+um2tpuxINHWy3GhiccY7QgEaVHQ==
tsscmp@1.0.6, tsscmp@^1.0.6:
version "1.0.6"
resolved "https://registry.yarnpkg.com/tsscmp/-/tsscmp-1.0.6.tgz#85b99583ac3589ec4bfef825b5000aa911d605eb"