Skip to content

Commit abb9a6f

Browse files
committed
fixup! feat: Add slots for video and file upload components and alerts
1 parent 1fe0323 commit abb9a6f

4 files changed

Lines changed: 78 additions & 59 deletions

File tree

src/plugin-slots/CourseFilesSlot/README.md

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Course Files Slot
22

3-
### Slot ID: `files_upload_page_table_slot`
3+
### Slot ID: `org.openedx.frontend.authoring.files_upload_page_table.v1`
44

55
## Description
66

@@ -11,14 +11,15 @@ This slot is used to replace/modify/hide the course file table UI.
1111
### Wrapped with a div with dashed border
1212
![Red Border around Files UI](./screenshot_files_border_wrap.png)
1313

14-
The following `env.config.jsx` will wrap the files component with a div that has a large red dashed redborder.
14+
The following `env.config.jsx` will wrap the files component with a div that has a large red dashed
15+
red border.
1516

1617
```js
1718
import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
1819

1920
const config = {
2021
pluginSlots: {
21-
files_upload_page_table_slot: {
22+
'org.openedx.frontend.authoring.files_upload_page_table.v1': {
2223
keepDefault: true,
2324
plugins: [
2425
{

src/plugin-slots/CourseFilesSlot/index.jsx

Lines changed: 19 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,18 @@ const CourseFilesSlot = ({ courseId }) => {
3333
usageStatus: usagePathStatus,
3434
errors: errorMessages,
3535
} = useSelector(state => state.assets);
36-
const data = {
37-
fileIds: assetIds,
38-
loadingStatus,
39-
usagePathStatus,
40-
usageErrorMessages: errorMessages.usageMetrics,
41-
fileType: 'file',
42-
};
36+
4337
const handleErrorReset = (error) => dispatch(resetErrors(error));
4438
const handleDeleteFile = (id) => dispatch(deleteAssetFile(courseId, id));
4539
const handleDownloadFile = (selectedRows) => dispatch(fetchAssetDownload({ selectedRows, courseId }));
4640
const handleAddFile = (files) => {
4741
handleErrorReset({ errorType: 'add' });
4842
dispatch(validateAssetFiles(courseId, files));
4943
};
44+
const handleFileOverwrite = (close, files) => {
45+
Object.values(files).forEach(file => dispatch(addAssetFile(courseId, file, true)));
46+
close();
47+
};
5048
const handleLockFile = (fileId, locked) => {
5149
handleErrorReset({ errorType: 'lock' });
5250
dispatch(updateAssetLock({ courseId, assetId: fileId, locked }));
@@ -56,22 +54,25 @@ const CourseFilesSlot = ({ courseId }) => {
5654
dispatch(updateAssetOrder(courseId, newFileIdOrder, sortType));
5755
};
5856

59-
const handleFileOverwrite = (close, files) => {
60-
Object.values(files).forEach(file => dispatch(addAssetFile(courseId, file, true)));
61-
close();
62-
};
63-
6457
const thumbnailPreview = (props) => FileThumbnail(props);
6558
const infoModalSidebar = (asset) => FileInfoModalSidebar({
6659
asset,
6760
handleLockedAsset: handleLockFile,
6861
});
62+
6963
const assets = useModels('assets', assetIds);
64+
const data = {
65+
fileIds: assetIds,
66+
loadingStatus,
67+
usagePathStatus,
68+
usageErrorMessages: errorMessages.usageMetrics,
69+
fileType: 'file',
70+
};
7071
const maxFileSize = 20 * 1048576;
7172

7273
const activeColumn = {
7374
id: 'activeStatus',
74-
Header: 'Active',
75+
Header: intl.formatMessage(messages.fileActiveColumn),
7576
accessor: 'activeStatus',
7677
Cell: ({ row }) => ActiveColumn({ row, pageLoadStatus: loadingStatus }),
7778
Filter: CheckboxFilter,
@@ -83,7 +84,7 @@ const CourseFilesSlot = ({ courseId }) => {
8384
};
8485
const accessColumn = {
8586
id: 'lockStatus',
86-
Header: 'Access',
87+
Header: intl.formatMessage(messages.fileAccessColumn),
8788
accessor: 'lockStatus',
8889
Cell: ({ row }) => AccessColumn({ row }),
8990
Filter: CheckboxFilter,
@@ -99,7 +100,7 @@ const CourseFilesSlot = ({ courseId }) => {
99100
};
100101
const fileSizeColumn = {
101102
id: 'fileSize',
102-
Header: 'File size',
103+
Header: intl.formatMessage(messages.fileSizeColumn),
103104
accessor: 'fileSize',
104105
Cell: ({ row }) => {
105106
const { fileSize } = row.original;
@@ -110,12 +111,12 @@ const CourseFilesSlot = ({ courseId }) => {
110111
const tableColumns = [
111112
{ ...thumbnailColumn },
112113
{
113-
Header: 'File name',
114+
Header: intl.formatMessage(messages.fileNameColumn),
114115
accessor: 'displayName',
115116
},
116117
{ ...fileSizeColumn },
117118
{
118-
Header: 'Type',
119+
Header: intl.formatMessage(messages.fileTypeColumn),
119120
accessor: 'wrapperType',
120121
Filter: CheckboxFilter,
121122
filter: 'includesValue',
@@ -146,7 +147,7 @@ const CourseFilesSlot = ({ courseId }) => {
146147
{ ...accessColumn },
147148
];
148149
return (
149-
<PluginSlot id="files_upload_page_table_slot">
150+
<PluginSlot id="org.openedx.frontend.authoring.files_upload_page_table.v1">
150151
<FileTable
151152
{...{
152153
courseId,

src/plugin-slots/CourseVideosSlot/README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Course Video Upload Page Slot
22

3-
### Slot ID: `videos_upload_page_table_slot`
3+
### Slot ID: `org.openedx.frontend.authoring.videos_upload_page_table.v1`
44

55
## Description
66

@@ -18,7 +18,7 @@ import { PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
1818

1919
const config = {
2020
pluginSlots: {
21-
videos_upload_page_table_slot: {
21+
'org.openedx.frontend.authoring.videos_upload_page_table.v1': {
2222
keepDefault: true,
2323
plugins: [
2424
{

src/plugin-slots/CourseVideosSlot/index.jsx

Lines changed: 53 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import {
1717
addVideoThumbnail, cancelAllUploads,
1818
deleteVideoFile,
1919
fetchVideoDownload, fetchVideos,
20-
getUsagePaths, markVideoUploadsInProgressAsFailed, resetErrors,
20+
getUsagePaths, markVideoUploadsInProgressAsFailed, newUploadData, resetErrors,
2121
updateVideoOrder,
2222
} from 'CourseAuthoring/files-and-videos/videos-page/data/thunks';
2323
import { getFormattedDuration, resampleFile } from 'CourseAuthoring/files-and-videos/videos-page/data/utils';
@@ -26,7 +26,7 @@ import messages from 'CourseAuthoring/files-and-videos/videos-page/messages';
2626
import TranscriptSettings from 'CourseAuthoring/files-and-videos/videos-page/transcript-settings';
2727
import UploadModal from 'CourseAuthoring/files-and-videos/videos-page/upload-modal';
2828
import VideoThumbnail from 'CourseAuthoring/files-and-videos/videos-page/VideoThumbnail';
29-
import { useModels } from 'CourseAuthoring/generic/model-store';
29+
import { useModel, useModels } from 'CourseAuthoring/generic/model-store';
3030
import PropTypes from 'prop-types';
3131
import React, { useEffect, useRef } from 'react';
3232
import { useDispatch, useSelector } from 'react-redux';
@@ -39,6 +39,15 @@ const CourseVideosSlot = ({ courseId }) => {
3939
openTranscriptSettings,
4040
closeTranscriptSettings,
4141
] = useToggle(false);
42+
const [
43+
isUploadTrackerOpen,
44+
openUploadTracker,
45+
closeUploadTracker,
46+
] = useToggle(false);
47+
48+
useEffect(() => {
49+
dispatch(fetchVideos(courseId));
50+
}, [courseId]);
4251
const {
4352
videoIds,
4453
loadingStatus,
@@ -51,6 +60,30 @@ const CourseVideosSlot = ({ courseId }) => {
5160

5261
const uploadingIdsRef = useRef({ uploadData: {}, uploadCount: 0 });
5362

63+
useEffect(() => {
64+
window.onbeforeunload = () => {
65+
dispatch(markVideoUploadsInProgressAsFailed({ uploadingIdsRef, courseId }));
66+
if (addVideoStatus === RequestStatus.IN_PROGRESS) {
67+
return '';
68+
}
69+
return undefined;
70+
};
71+
switch (addVideoStatus) {
72+
case RequestStatus.IN_PROGRESS:
73+
openUploadTracker();
74+
break;
75+
case RequestStatus.SUCCESSFUL:
76+
setTimeout(() => closeUploadTracker(), 500);
77+
break;
78+
case RequestStatus.FAILED:
79+
setTimeout(() => closeUploadTracker(), 500);
80+
break;
81+
default:
82+
closeUploadTracker();
83+
break;
84+
}
85+
}, [addVideoStatus]);
86+
5487
const {
5588
isVideoTranscriptEnabled,
5689
encodingsDownloadUrl,
@@ -66,6 +99,18 @@ const CourseVideosSlot = ({ courseId }) => {
6699
const handleAddFile = (files) => {
67100
handleErrorReset({ errorType: 'add' });
68101
uploadingIdsRef.current.uploadCount = files.length;
102+
103+
files.forEach((file, idx) => {
104+
const name = file?.name || `Video ${idx + 1}`;
105+
const progress = 0;
106+
107+
newUploadData({
108+
status: RequestStatus.PENDING,
109+
currentData: uploadingIdsRef.current.uploadData,
110+
originalValue: { name, progress },
111+
key: `video_${idx}`,
112+
});
113+
});
69114
dispatch(addVideoFile(courseId, files, videoIds, uploadingIdsRef));
70115
};
71116
const handleDeleteFile = (id) => dispatch(deleteVideoFile(courseId, id));
@@ -81,40 +126,8 @@ const CourseVideosSlot = ({ courseId }) => {
81126
videoId,
82127
addVideoThumbnail,
83128
});
84-
const videos = useModels('videos', videoIds);
85-
const [
86-
isUploadTrackerOpen,
87-
openUploadTracker,
88-
closeUploadTracker,
89-
] = useToggle(false);
90-
91-
useEffect(() => {
92-
dispatch(fetchVideos(courseId));
93-
}, [courseId]);
94129

95-
useEffect(() => {
96-
window.onbeforeunload = () => {
97-
dispatch(markVideoUploadsInProgressAsFailed({ uploadingIdsRef, courseId }));
98-
if (addVideoStatus === RequestStatus.IN_PROGRESS) {
99-
return '';
100-
}
101-
return undefined;
102-
};
103-
switch (addVideoStatus) {
104-
case RequestStatus.IN_PROGRESS:
105-
openUploadTracker();
106-
break;
107-
case RequestStatus.SUCCESSFUL:
108-
setTimeout(() => closeUploadTracker(), 500);
109-
break;
110-
case RequestStatus.FAILED:
111-
setTimeout(() => closeUploadTracker(), 500);
112-
break;
113-
default:
114-
closeUploadTracker();
115-
break;
116-
}
117-
}, [addVideoStatus]);
130+
const videos = useModels('videos', videoIds);
118131

119132
const data = {
120133
supportedFileFormats,
@@ -202,14 +215,18 @@ const CourseVideosSlot = ({ courseId }) => {
202215
{ ...activeColumn },
203216
{ ...processingStatusColumn },
204217
];
218+
205219
return (
206220
<PluginSlot
207-
id="videos_upload_page_table_slot"
221+
id="org.openedx.frontend.authoring.videos_upload_page_table.v1"
208222
pluginProps={{
209223
courseId,
210224
}}
211225
>
212226
<ActionRow>
227+
<div className="h2">
228+
{intl.formatMessage(messages.heading)}
229+
</div>
213230
<ActionRow.Spacer />
214231
{isVideoTranscriptEnabled ? (
215232
<Button

0 commit comments

Comments
 (0)