style: adding more styles on the selection modal
This commit is contained in:
34
package-lock.json
generated
34
package-lock.json
generated
@@ -21,6 +21,7 @@
|
||||
"codemirror": "^6.0.0",
|
||||
"fast-xml-parser": "^4.0.10",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment-shortformat": "^2.1.0",
|
||||
"react-redux": "^7.2.8",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.2",
|
||||
@@ -26149,6 +26150,27 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-shortformat": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/moment-shortformat/-/moment-shortformat-2.1.0.tgz",
|
||||
"integrity": "sha512-TBh8jH4cVQOnZU+fQXkyCgj74ti//0CTdQd5sQLDTZuHLMaUP3uFEhbfb3yrrLYNVzgoiUhyiIMf0rDdn5iTJg==",
|
||||
"deprecated": "Package is no longer maintained",
|
||||
"engines": {
|
||||
"node": ">= 4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"moment": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/moo": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
|
||||
@@ -54618,6 +54640,18 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.4",
|
||||
"resolved": "https://registry.npmjs.org/moment/-/moment-2.29.4.tgz",
|
||||
"integrity": "sha512-5LC9SOxjSc2HF6vO2CyuTDNivEdoz2IvyJJGj6X8DJ0eFyfszE0QiEd+iXmBvUP3WHxSjFH/vIsA0EN00cgr8w==",
|
||||
"peer": true
|
||||
},
|
||||
"moment-shortformat": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/moment-shortformat/-/moment-shortformat-2.1.0.tgz",
|
||||
"integrity": "sha512-TBh8jH4cVQOnZU+fQXkyCgj74ti//0CTdQd5sQLDTZuHLMaUP3uFEhbfb3yrrLYNVzgoiUhyiIMf0rDdn5iTJg==",
|
||||
"requires": {}
|
||||
},
|
||||
"moo": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/moo/-/moo-0.5.2.tgz",
|
||||
|
||||
@@ -69,6 +69,7 @@
|
||||
"codemirror": "^6.0.0",
|
||||
"fast-xml-parser": "^4.0.10",
|
||||
"lodash-es": "^4.17.21",
|
||||
"moment-shortformat": "^2.1.0",
|
||||
"react-redux": "^7.2.8",
|
||||
"react-responsive": "8.2.0",
|
||||
"react-transition-group": "4.4.2",
|
||||
|
||||
@@ -4,7 +4,7 @@ import PropTypes from 'prop-types';
|
||||
import VideoGallery from './containers/VideoGallery';
|
||||
import * as hooks from './hooks';
|
||||
|
||||
export const Selector = ({
|
||||
export const VideoSelector = ({
|
||||
learningContextId,
|
||||
lmsEndpointUrl,
|
||||
studioEndpointUrl,
|
||||
@@ -25,10 +25,10 @@ export const Selector = ({
|
||||
);
|
||||
};
|
||||
|
||||
Selector.propTypes = {
|
||||
VideoSelector.propTypes = {
|
||||
learningContextId: PropTypes.string.isRequired,
|
||||
lmsEndpointUrl: PropTypes.string.isRequired,
|
||||
studioEndpointUrl: PropTypes.string.isRequired,
|
||||
};
|
||||
|
||||
export default Selector;
|
||||
export default VideoSelector;
|
||||
@@ -2,7 +2,7 @@ import React from 'react';
|
||||
import { useDispatch } from 'react-redux';
|
||||
import { shallow } from 'enzyme';
|
||||
import * as hooks from './hooks';
|
||||
import Selector from './Selector';
|
||||
import VideoSelector from './VideoSelector';
|
||||
|
||||
jest.mock('./hooks', () => ({
|
||||
initializeApp: jest.fn(),
|
||||
@@ -22,15 +22,15 @@ const initData = {
|
||||
...props,
|
||||
};
|
||||
|
||||
describe('Editor', () => {
|
||||
describe('Video Selector', () => {
|
||||
describe('render', () => {
|
||||
test('rendering correctly with expected Input', () => {
|
||||
expect(shallow(<Selector {...props} />)).toMatchSnapshot();
|
||||
expect(shallow(<VideoSelector {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
describe('behavior', () => {
|
||||
it('calls initializeApp hook with dispatch, and passed data', () => {
|
||||
shallow(<Selector {...props} />);
|
||||
shallow(<VideoSelector {...props} />);
|
||||
expect(hooks.initializeApp).toHaveBeenCalledWith({
|
||||
dispatch: useDispatch(),
|
||||
data: initData,
|
||||
@@ -2,17 +2,17 @@ import React from 'react';
|
||||
import { Provider } from 'react-redux';
|
||||
import PropTypes from 'prop-types';
|
||||
import ErrorBoundary from './sharedComponents/ErrorBoundary';
|
||||
import { Selector } from './Selector';
|
||||
import { VideoSelector } from './VideoSelector';
|
||||
import store from './data/store';
|
||||
|
||||
const SelectorPage = ({
|
||||
const VideoSelectorPage = ({
|
||||
courseId,
|
||||
lmsEndpointUrl,
|
||||
studioEndpointUrl,
|
||||
}) => (
|
||||
<ErrorBoundary>
|
||||
<Provider store={store}>
|
||||
<Selector
|
||||
<VideoSelector
|
||||
{...{
|
||||
learningContextId: courseId,
|
||||
lmsEndpointUrl,
|
||||
@@ -23,16 +23,16 @@ const SelectorPage = ({
|
||||
</ErrorBoundary>
|
||||
);
|
||||
|
||||
SelectorPage.defaultProps = {
|
||||
VideoSelectorPage.defaultProps = {
|
||||
courseId: null,
|
||||
lmsEndpointUrl: null,
|
||||
studioEndpointUrl: null,
|
||||
};
|
||||
|
||||
SelectorPage.propTypes = {
|
||||
VideoSelectorPage.propTypes = {
|
||||
courseId: PropTypes.string,
|
||||
lmsEndpointUrl: PropTypes.string,
|
||||
studioEndpointUrl: PropTypes.string,
|
||||
};
|
||||
|
||||
export default SelectorPage;
|
||||
export default VideoSelectorPage;
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from 'react';
|
||||
import { shallow } from 'enzyme';
|
||||
import SelectorPage from './SelectorPage';
|
||||
import VideoSelectorPage from './VideoSelectorPage';
|
||||
|
||||
const props = {
|
||||
courseId: 'course-v1:edX+DemoX+Demo_Course',
|
||||
@@ -11,15 +11,15 @@ const props = {
|
||||
jest.mock('react-redux', () => ({
|
||||
Provider: 'Provider',
|
||||
}));
|
||||
jest.mock('./Selector', () => 'Selector');
|
||||
jest.mock('./VideoSelector', () => 'VideoSelector');
|
||||
|
||||
describe('Selector Page', () => {
|
||||
describe('Video Selector Page', () => {
|
||||
describe('snapshots', () => {
|
||||
test('rendering correctly with expected Input', () => {
|
||||
expect(shallow(<SelectorPage {...props} />)).toMatchSnapshot();
|
||||
expect(shallow(<VideoSelectorPage {...props} />)).toMatchSnapshot();
|
||||
});
|
||||
test('rendering with props to null', () => {
|
||||
expect(shallow(<SelectorPage />)).toMatchSnapshot();
|
||||
expect(shallow(<VideoSelectorPage />)).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -1,3 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Editor render rendering correctly with expected Input 1`] = `<VideoGallery />`;
|
||||
3
src/editors/__snapshots__/VideoSelector.test.jsx.snap
Normal file
3
src/editors/__snapshots__/VideoSelector.test.jsx.snap
Normal file
@@ -0,0 +1,3 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Video Selector render rendering correctly with expected Input 1`] = `<VideoGallery />`;
|
||||
@@ -1,6 +1,6 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`Selector Page snapshots rendering correctly with expected Input 1`] = `
|
||||
exports[`Video Selector Page snapshots rendering correctly with expected Input 1`] = `
|
||||
<ErrorBoundary>
|
||||
<Provider
|
||||
store={
|
||||
@@ -22,7 +22,7 @@ exports[`Selector Page snapshots rendering correctly with expected Input 1`] = `
|
||||
</ErrorBoundary>
|
||||
`;
|
||||
|
||||
exports[`Selector Page snapshots rendering with props to null 1`] = `
|
||||
exports[`Video Selector Page snapshots rendering with props to null 1`] = `
|
||||
<ErrorBoundary>
|
||||
<Provider
|
||||
store={
|
||||
@@ -5,6 +5,7 @@ exports[`EditorContainer component render snapshot: initialized. enable save and
|
||||
className="position-relative zindex-0"
|
||||
>
|
||||
<BaseModal
|
||||
bodyStyle={null}
|
||||
close={[MockFunction closeCancelConfirmModal]}
|
||||
confirmAction={
|
||||
<Button
|
||||
@@ -25,6 +26,7 @@ exports[`EditorContainer component render snapshot: initialized. enable save and
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
headerComponent={null}
|
||||
isFullscreenScroll={true}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
@@ -84,6 +86,7 @@ exports[`EditorContainer component render snapshot: not initialized. disable sav
|
||||
className="position-relative zindex-0"
|
||||
>
|
||||
<BaseModal
|
||||
bodyStyle={null}
|
||||
close={[MockFunction closeCancelConfirmModal]}
|
||||
confirmAction={
|
||||
<Button
|
||||
@@ -104,6 +107,7 @@ exports[`EditorContainer component render snapshot: not initialized. disable sav
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
headerComponent={null}
|
||||
isFullscreenScroll={true}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
|
||||
@@ -10,6 +10,9 @@ jest.mock('../../../../../data/redux', () => ({
|
||||
problemType: jest.fn(state => ({ problemType: state })),
|
||||
},
|
||||
},
|
||||
thunkActions: {
|
||||
video: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('AnswerOption', () => {
|
||||
|
||||
@@ -21,6 +21,11 @@ jest.mock('../../../../../data/redux', () => ({
|
||||
question: jest.fn(state => ({ question: state })),
|
||||
},
|
||||
},
|
||||
thunkActions: {
|
||||
video: {
|
||||
importTranscript: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('../../../../../sharedComponents/TinyMceWidget/hooks', () => ({
|
||||
|
||||
@@ -16,6 +16,9 @@ jest.mock('../../../../../../data/redux', () => ({
|
||||
learningContextId: jest.fn(state => ({ learningContextId: state })),
|
||||
},
|
||||
},
|
||||
thunkActions: {
|
||||
video: jest.fn(),
|
||||
},
|
||||
}));
|
||||
|
||||
describe('ShowAnswerCard', () => {
|
||||
|
||||
@@ -5,6 +5,7 @@ exports[`SwitchToAdvancedEditorCard snapshot snapshot: SwitchToAdvancedEditorCar
|
||||
className="border border-light-700 shadow-none"
|
||||
>
|
||||
<BaseModal
|
||||
bodyStyle={null}
|
||||
close={[Function]}
|
||||
confirmAction={
|
||||
<Button
|
||||
@@ -21,6 +22,7 @@ exports[`SwitchToAdvancedEditorCard snapshot snapshot: SwitchToAdvancedEditorCar
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
headerComponent={null}
|
||||
isFullscreenScroll={true}
|
||||
isOpen={false}
|
||||
size="md"
|
||||
|
||||
@@ -61,6 +61,11 @@ jest.mock('../../data/redux', () => ({
|
||||
isFinished: jest.fn((state, params) => ({ isFailed: { state, params } })),
|
||||
},
|
||||
},
|
||||
thunkActions: {
|
||||
video: {
|
||||
importTranscript: jest.fn(),
|
||||
},
|
||||
},
|
||||
}));
|
||||
|
||||
describe('TextEditor', () => {
|
||||
|
||||
@@ -139,20 +139,34 @@ export const buildVideos = ({ rawVideos }) => {
|
||||
let videos = [];
|
||||
const videoList = Object.values(rawVideos);
|
||||
if (videoList.length > 0) {
|
||||
videos = videoList.map(asset => ({
|
||||
id: asset.edx_video_id,
|
||||
displayName: asset.client_video_id,
|
||||
externalUrl: asset.course_video_image_url,
|
||||
dateAdded: asset.created,
|
||||
videos = videoList.map(video => ({
|
||||
id: video.edx_video_id,
|
||||
displayName: video.client_video_id,
|
||||
externalUrl: video.course_video_image_url,
|
||||
dateAdded: video.created,
|
||||
locked: false,
|
||||
thumbnail: asset.course_video_image_url,
|
||||
status: asset.status,
|
||||
duration: asset.duration,
|
||||
thumbnail: video.course_video_image_url,
|
||||
status: video.status,
|
||||
statusBadgeVariant: module.getstatusBadgeVariant({ status: video.status }),
|
||||
duration: video.duration,
|
||||
transcripts: video.transcripts,
|
||||
}));
|
||||
}
|
||||
return videos;
|
||||
};
|
||||
|
||||
export const getstatusBadgeVariant = ({ status }) => {
|
||||
switch (status) {
|
||||
case filterKeys.failed:
|
||||
return 'danger';
|
||||
case filterKeys.uploading:
|
||||
case filterKeys.processing:
|
||||
return 'light';
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
export const videoHooks = ({ videos }) => {
|
||||
const searchSortProps = module.searchAndSortHooks();
|
||||
const videoList = module.videoListHooks({ searchSortProps, videos });
|
||||
|
||||
@@ -10,12 +10,20 @@ exports[`BaseModal ImageUploadModal template component snapshot 1`] = `
|
||||
size="lg"
|
||||
variant="default"
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Header
|
||||
style={
|
||||
Object {
|
||||
"zIndex": 10000,
|
||||
}
|
||||
}
|
||||
>
|
||||
<ModalDialog.Title>
|
||||
props.title node
|
||||
</ModalDialog.Title>
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<ModalDialog.Body
|
||||
style={null}
|
||||
>
|
||||
props.children node
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
|
||||
@@ -14,10 +14,12 @@ export const BaseModal = ({
|
||||
close,
|
||||
title,
|
||||
children,
|
||||
headerComponent,
|
||||
confirmAction,
|
||||
footerAction,
|
||||
size,
|
||||
isFullscreenScroll,
|
||||
bodyStyle,
|
||||
}) => (
|
||||
<ModalDialog
|
||||
isOpen={isOpen}
|
||||
@@ -28,12 +30,13 @@ export const BaseModal = ({
|
||||
isFullscreenOnMobile
|
||||
isFullscreenScroll={isFullscreenScroll}
|
||||
>
|
||||
<ModalDialog.Header>
|
||||
<ModalDialog.Header style={{ zIndex: 10000 }}>
|
||||
<ModalDialog.Title>
|
||||
{title}
|
||||
</ModalDialog.Title>
|
||||
{headerComponent}
|
||||
</ModalDialog.Header>
|
||||
<ModalDialog.Body>
|
||||
<ModalDialog.Body style={bodyStyle}>
|
||||
{children}
|
||||
</ModalDialog.Body>
|
||||
<ModalDialog.Footer>
|
||||
@@ -51,8 +54,10 @@ export const BaseModal = ({
|
||||
|
||||
BaseModal.defaultProps = {
|
||||
footerAction: null,
|
||||
headerComponent: null,
|
||||
size: 'lg',
|
||||
isFullscreenScroll: true,
|
||||
bodyStyle: null,
|
||||
};
|
||||
|
||||
BaseModal.propTypes = {
|
||||
@@ -62,8 +67,10 @@ BaseModal.propTypes = {
|
||||
children: PropTypes.node.isRequired,
|
||||
confirmAction: PropTypes.node.isRequired,
|
||||
footerAction: PropTypes.node,
|
||||
headerComponent: PropTypes.node,
|
||||
size: PropTypes.string,
|
||||
isFullscreenScroll: PropTypes.bool,
|
||||
bodyStyle: PropTypes.shape({}),
|
||||
};
|
||||
|
||||
export default BaseModal;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
exports[`ImageSettingsModal render snapshot 1`] = `
|
||||
<BaseModal
|
||||
bodyStyle={null}
|
||||
close={[MockFunction props.close]}
|
||||
confirmAction={
|
||||
<Button
|
||||
@@ -35,6 +36,7 @@ exports[`ImageSettingsModal render snapshot 1`] = `
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
headerComponent={null}
|
||||
isFullscreenScroll={true}
|
||||
isOpen={false}
|
||||
size="lg"
|
||||
|
||||
@@ -9,7 +9,6 @@ import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
intlShape,
|
||||
MessageDescriptor,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
import messages from './messages';
|
||||
@@ -39,20 +38,20 @@ export const Gallery = ({
|
||||
}
|
||||
if (galleryIsEmpty) {
|
||||
return (
|
||||
<div className="gallery p-4 bg-gray-100" style={{ height }}>
|
||||
<div className="gallery p-4 bg-gray-100" style={{ height, margin: '0 -1.5rem' }}>
|
||||
<FormattedMessage {...emptyGalleryLabel} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
if (searchIsEmpty) {
|
||||
return (
|
||||
<div className="gallery p-4 bg-gray-100" style={{ height }}>
|
||||
<div className="gallery p-4 bg-gray-100" style={{ height, margin: '0 -1.5rem' }}>
|
||||
<FormattedMessage {...messages.emptySearchLabel} />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
return (
|
||||
<Scrollable className="gallery bg-gray-100" style={{ height }}>
|
||||
<Scrollable className="gallery bg-gray-100" style={{ height, margin: '0 -1.5rem' }}>
|
||||
<div className="p-4">
|
||||
<SelectableBox.Set
|
||||
columns={1}
|
||||
@@ -72,7 +71,6 @@ Gallery.defaultProps = {
|
||||
highlighted: '',
|
||||
showIdsOnCards: false,
|
||||
height: '375px',
|
||||
emptyGalleryLabel: null,
|
||||
};
|
||||
Gallery.propTypes = {
|
||||
isLoaded: PropTypes.bool.isRequired,
|
||||
@@ -81,7 +79,7 @@ Gallery.propTypes = {
|
||||
displayList: PropTypes.arrayOf(PropTypes.object).isRequired,
|
||||
highlighted: PropTypes.string,
|
||||
onHighlightChange: PropTypes.func.isRequired,
|
||||
emptyGalleryLabel: MessageDescriptor,
|
||||
emptyGalleryLabel: PropTypes.shape({}).isRequired,
|
||||
showIdsOnCards: PropTypes.bool,
|
||||
height: PropTypes.string,
|
||||
// injected
|
||||
|
||||
@@ -2,36 +2,53 @@ import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
import {
|
||||
Button,
|
||||
Icon,
|
||||
Badge,
|
||||
Image,
|
||||
SelectableBox,
|
||||
} from '@edx/paragon';
|
||||
import { FormattedMessage, FormattedDate, FormattedTime } from '@edx/frontend-platform/i18n';
|
||||
import { Link } from '@edx/paragon/icons';
|
||||
|
||||
import messages from './messages';
|
||||
import { formatDuration } from '../../utils';
|
||||
import LanguageNamesWidget from '../../containers/VideoEditor/components/VideoSettingsModal/components/VideoPreviewWidget/LanguageNamesWidget';
|
||||
|
||||
export const GalleryCard = ({
|
||||
asset,
|
||||
showId,
|
||||
}) => (
|
||||
<SelectableBox className="card bg-white" key={asset.externalUrl} type="radio" value={asset.id}>
|
||||
<SelectableBox className="card bg-white" key={asset.externalUrl} type="radio" value={asset.id} style={{ padding: '10px 20px' }}>
|
||||
<div className="card-div d-flex flex-row flex-nowrap">
|
||||
<Image
|
||||
style={{ width: '100px', height: '100px' }}
|
||||
src={asset.externalUrl}
|
||||
/>
|
||||
<div className="img-text p-3">
|
||||
<h3>{asset.displayName}</h3>
|
||||
{ showId && (
|
||||
<p>
|
||||
<Button variant="link" size="inline" onClick={() => { /* TODO */ }}>
|
||||
<Icon src={Link} /> {asset.id}
|
||||
</Button>
|
||||
</p>
|
||||
<div style={{
|
||||
position: 'relative',
|
||||
width: '200px',
|
||||
height: '100px',
|
||||
margin: '16px 0 0 0',
|
||||
}}
|
||||
>
|
||||
<Image
|
||||
style={{ width: '200px', height: '100px' }}
|
||||
src={asset.externalUrl}
|
||||
/>
|
||||
{ asset.status && asset.statusBadgeVariant && (
|
||||
<Badge variant={asset.statusBadgeVariant} style={{ position: 'absolute', left: '6px', top: '6px' }}>
|
||||
{asset.status}
|
||||
</Badge>
|
||||
)}
|
||||
<p>
|
||||
{ asset.duration >= 0 && (
|
||||
<Badge variant="dark" style={{ position: 'absolute', right: '6px', bottom: '6px' }}>
|
||||
{formatDuration(asset.duration)}
|
||||
</Badge>
|
||||
)}
|
||||
</div>
|
||||
<div className="card-text p-3">
|
||||
<h3>{asset.displayName}</h3>
|
||||
{ asset.transcripts && (
|
||||
<div style={{ margin: '0 0 5px 0' }}>
|
||||
<LanguageNamesWidget
|
||||
transcripts={asset.transcripts}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
<p style={{ fontSize: '11px' }}>
|
||||
<FormattedMessage
|
||||
{...messages.addedDate}
|
||||
values={{
|
||||
@@ -45,10 +62,6 @@ export const GalleryCard = ({
|
||||
</SelectableBox>
|
||||
);
|
||||
|
||||
GalleryCard.defaultProps = {
|
||||
showId: false,
|
||||
};
|
||||
|
||||
GalleryCard.propTypes = {
|
||||
asset: PropTypes.shape({
|
||||
contentType: PropTypes.string,
|
||||
@@ -62,8 +75,9 @@ GalleryCard.propTypes = {
|
||||
url: PropTypes.string,
|
||||
duration: PropTypes.number,
|
||||
status: PropTypes.string,
|
||||
statusBadgeVariant: PropTypes.string,
|
||||
transcripts: PropTypes.array,
|
||||
}).isRequired,
|
||||
showId: PropTypes.bool,
|
||||
};
|
||||
|
||||
export default GalleryCard;
|
||||
|
||||
@@ -8,7 +8,6 @@ import { Close, Search } from '@edx/paragon/icons';
|
||||
import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
MessageDescriptor,
|
||||
intlShape,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
@@ -109,7 +108,6 @@ SearchSort.defaultProps = {
|
||||
filterKeys: null,
|
||||
filterMessages: null,
|
||||
showSwitch: false,
|
||||
switchMessage: null,
|
||||
onSwitchClick: null,
|
||||
};
|
||||
|
||||
@@ -126,7 +124,7 @@ SearchSort.propTypes = {
|
||||
filterKeys: PropTypes.shape({}),
|
||||
filterMessages: PropTypes.shape({}),
|
||||
showSwitch: PropTypes.bool,
|
||||
switchMessage: MessageDescriptor,
|
||||
switchMessage: PropTypes.shape({}).isRequired,
|
||||
onSwitchClick: PropTypes.func,
|
||||
// injected
|
||||
intl: intlShape.isRequired,
|
||||
|
||||
@@ -6,6 +6,7 @@ exports[`TextEditor Image Gallery component component snapshot: loaded but no im
|
||||
style={
|
||||
Object {
|
||||
"height": "375px",
|
||||
"margin": "0 -1.5rem",
|
||||
}
|
||||
}
|
||||
>
|
||||
@@ -19,6 +20,7 @@ exports[`TextEditor Image Gallery component component snapshot: loaded but searc
|
||||
style={
|
||||
Object {
|
||||
"height": "375px",
|
||||
"margin": "0 -1.5rem",
|
||||
}
|
||||
}
|
||||
>
|
||||
@@ -36,6 +38,7 @@ exports[`TextEditor Image Gallery component component snapshot: loaded, show gal
|
||||
style={
|
||||
Object {
|
||||
"height": "375px",
|
||||
"margin": "0 -1.5rem",
|
||||
}
|
||||
}
|
||||
>
|
||||
|
||||
@@ -4,27 +4,49 @@ exports[`GalleryCard component snapshot: dateAdded=12345 1`] = `
|
||||
<SelectableBox
|
||||
className="card bg-white"
|
||||
key="props.img.externalUrl"
|
||||
style={
|
||||
Object {
|
||||
"padding": "10px 20px",
|
||||
}
|
||||
}
|
||||
type="radio"
|
||||
>
|
||||
<div
|
||||
className="card-div d-flex flex-row flex-nowrap"
|
||||
>
|
||||
<Image
|
||||
src="props.img.externalUrl"
|
||||
<div
|
||||
style={
|
||||
Object {
|
||||
"height": "100px",
|
||||
"width": "100px",
|
||||
"margin": "16px 0 0 0",
|
||||
"position": "relative",
|
||||
"width": "200px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
>
|
||||
<Image
|
||||
src="props.img.externalUrl"
|
||||
style={
|
||||
Object {
|
||||
"height": "100px",
|
||||
"width": "200px",
|
||||
}
|
||||
}
|
||||
/>
|
||||
</div>
|
||||
<div
|
||||
className="img-text p-3"
|
||||
className="card-text p-3"
|
||||
>
|
||||
<h3>
|
||||
props.img.displayName
|
||||
</h3>
|
||||
<p>
|
||||
<p
|
||||
style={
|
||||
Object {
|
||||
"fontSize": "11px",
|
||||
}
|
||||
}
|
||||
>
|
||||
<FormattedMessage
|
||||
defaultMessage="Added {date} at {time}"
|
||||
description="File date-added string"
|
||||
|
||||
@@ -6,7 +6,6 @@ import { Add } from '@edx/paragon/icons';
|
||||
import {
|
||||
FormattedMessage,
|
||||
injectIntl,
|
||||
MessageDescriptor,
|
||||
intlShape,
|
||||
} from '@edx/frontend-platform/i18n';
|
||||
|
||||
@@ -65,6 +64,12 @@ export const SelectionModal = ({
|
||||
</Button>
|
||||
)}
|
||||
title={intl.formatMessage(titleMsg)}
|
||||
bodyStyle={{ background: '#EBEBEB' }}
|
||||
headerComponent={(
|
||||
<div style={{ zIndex: 10000, margin: '18px 0' }}>
|
||||
<SearchSort {...searchSortProps} />
|
||||
</div>
|
||||
)}
|
||||
>
|
||||
{/* Error Alerts */}
|
||||
<FetchErrorAlert isFetchError={isFetchError} message={fetchError} />
|
||||
@@ -85,8 +90,7 @@ export const SelectionModal = ({
|
||||
>
|
||||
<FormattedMessage {...galleryError.message} />
|
||||
</ErrorAlert>
|
||||
<Stack gap={3}>
|
||||
<SearchSort {...searchSortProps} />
|
||||
<Stack gap={2}>
|
||||
<Gallery {...galleryPropsValues} />
|
||||
<FileInput fileInput={fileInput} acceptedFiles={Object.values(acceptedFiles).join()} />
|
||||
</Stack>
|
||||
@@ -108,13 +112,13 @@ SelectionModal.propTypes = {
|
||||
dismiss: PropTypes.func.isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
set: PropTypes.func.isRequired,
|
||||
message: MessageDescriptor,
|
||||
message: PropTypes.shape({}).isRequired,
|
||||
}).isRequired,
|
||||
inputError: PropTypes.shape({
|
||||
dismiss: PropTypes.func.isRequired,
|
||||
show: PropTypes.bool.isRequired,
|
||||
set: PropTypes.func.isRequired,
|
||||
message: MessageDescriptor,
|
||||
message: PropTypes.shape({}).isRequired,
|
||||
}).isRequired,
|
||||
fileInput: PropTypes.shape({
|
||||
click: PropTypes.func.isRequired,
|
||||
@@ -125,11 +129,11 @@ SelectionModal.propTypes = {
|
||||
selectBtnProps: PropTypes.shape({}).isRequired,
|
||||
acceptedFiles: PropTypes.shape({}).isRequired,
|
||||
modalMessages: PropTypes.shape({
|
||||
confirmMsg: MessageDescriptor,
|
||||
uploadButtonMsg: MessageDescriptor,
|
||||
titleMsg: MessageDescriptor,
|
||||
fetchError: MessageDescriptor,
|
||||
uploadError: MessageDescriptor,
|
||||
confirmMsg: PropTypes.shape({}).isRequired,
|
||||
uploadButtonMsg: PropTypes.shape({}).isRequired,
|
||||
titleMsg: PropTypes.shape({}).isRequired,
|
||||
fetchError: PropTypes.shape({}).isRequired,
|
||||
uploadError: PropTypes.shape({}).isRequired,
|
||||
}).isRequired,
|
||||
isLoaded: PropTypes.bool.isRequired,
|
||||
isFetchError: PropTypes.bool.isRequired,
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
exports[`SourceCodeModal renders as expected with default behavior 1`] = `
|
||||
<BaseModal
|
||||
bodyStyle={null}
|
||||
close={[MockFunction]}
|
||||
confirmAction={
|
||||
<Button
|
||||
@@ -24,6 +25,7 @@ exports[`SourceCodeModal renders as expected with default behavior 1`] = `
|
||||
</Button>
|
||||
}
|
||||
footerAction={null}
|
||||
headerComponent={null}
|
||||
isFullscreenScroll={true}
|
||||
isOpen={false}
|
||||
size="xl"
|
||||
|
||||
18
src/editors/utils/formatDuration.js
Normal file
18
src/editors/utils/formatDuration.js
Normal file
@@ -0,0 +1,18 @@
|
||||
import * as moment from 'moment-shortformat';
|
||||
|
||||
const formatDuration = (duration) => {
|
||||
const d = moment.duration(duration, 'seconds');
|
||||
if (d.hours > 0) {
|
||||
return (
|
||||
`${d.hours().toString().padStart(2, '0')}:`
|
||||
+ `${d.minutes().toString().padStart(2, '0')}:`
|
||||
+ `${d.seconds().toString().padStart(2, '0')}`
|
||||
);
|
||||
}
|
||||
return (
|
||||
`${d.minutes().toString().padStart(2, '0')}:`
|
||||
+ `${d.seconds().toString().padStart(2, '0')}`
|
||||
);
|
||||
};
|
||||
|
||||
export default formatDuration;
|
||||
@@ -3,3 +3,4 @@ export { default as StrictDict } from './StrictDict';
|
||||
export { default as keyStore } from './keyStore';
|
||||
export { default as camelizeKeys } from './camelizeKeys';
|
||||
export { default as removeItemOnce } from './removeOnce';
|
||||
export { default as formatDuration } from './formatDuration';
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import Placeholder from './Placeholder';
|
||||
import messages from './i18n/index';
|
||||
import EditorPage from './editors/EditorPage';
|
||||
import SelectorPage from './editors/SelectorPage';
|
||||
import VideoSelectorPage from './editors/VideoSelectorPage';
|
||||
|
||||
export { messages, EditorPage, SelectorPage };
|
||||
export { messages, EditorPage, VideoSelectorPage };
|
||||
export default Placeholder;
|
||||
|
||||
Reference in New Issue
Block a user