Skip to content

Commit d5fb054

Browse files
committed
feat: Add slots for video and file upload components and alerts
This change add plugin slots for the file and video upload components, and the alerts components on those pages.
1 parent c1d874f commit d5fb054

18 files changed

Lines changed: 736 additions & 535 deletions

File tree

src/course-outline/page-alerts/PageAlerts.jsx

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import CourseOutlinePageAlertsSlot from 'CourseAuthoring/plugin-slots/CourseOutlinePageAlertsSlot';
12
import React, { useState } from 'react';
23
import PropTypes from 'prop-types';
34
import { uniqBy } from 'lodash';
@@ -437,6 +438,7 @@ const PageAlerts = ({
437438
{conflictingFilesPasteAlert()}
438439
{newFilesPasteAlert()}
439440
{renderOutOfSyncAlert()}
441+
<CourseOutlinePageAlertsSlot />
440442
</>
441443
);
442444
};
Lines changed: 18 additions & 174 deletions
Original file line numberDiff line numberDiff line change
@@ -1,174 +1,40 @@
1-
import React, { useEffect } from 'react';
1+
import { useIntl } from '@edx/frontend-platform/i18n';
2+
import { Container } from '@openedx/paragon';
3+
import CourseFilesSlot from 'CourseAuthoring/plugin-slots/CourseFilesSlot';
24
import PropTypes from 'prop-types';
5+
import React, { useEffect } from 'react';
36
import { useDispatch, useSelector } from 'react-redux';
4-
import { injectIntl, FormattedMessage, intlShape } from '@edx/frontend-platform/i18n';
5-
import { CheckboxFilter, Container } from '@openedx/paragon';
6-
import Placeholder from '../../editors/Placeholder';
77

88
import { RequestStatus } from '../../data/constants';
9-
import { useModels, useModel } from '../../generic/model-store';
10-
import {
11-
addAssetFile,
12-
deleteAssetFile,
13-
fetchAssets,
14-
updateAssetLock,
15-
fetchAssetDownload,
16-
getUsagePaths,
17-
resetErrors,
18-
updateAssetOrder,
19-
validateAssetFiles,
20-
} from './data/thunks';
21-
import messages from './messages';
22-
import FilesPageProvider from './FilesPageProvider';
9+
import Placeholder from '../../editors/Placeholder';
10+
import { useModel } from '../../generic/model-store';
2311
import getPageHeadTitle from '../../generic/utils';
24-
import {
25-
AccessColumn,
26-
ActiveColumn,
27-
EditFileErrors,
28-
FileTable,
29-
ThumbnailColumn,
30-
} from '../generic';
31-
import { getFileSizeToClosestByte } from '../../utils';
32-
import FileThumbnail from './FileThumbnail';
33-
import FileInfoModalSidebar from './FileInfoModalSidebar';
34-
import FileValidationModal from './FileValidationModal';
12+
import { EditFileErrors } from '../generic';
13+
import { fetchAssets, resetErrors } from './data/thunks';
14+
import FilesPageProvider from './FilesPageProvider';
15+
import messages from './messages';
3516
import './FilesPage.scss';
3617

3718
const FilesPage = ({
3819
courseId,
39-
// injected
40-
intl,
4120
}) => {
4221
const dispatch = useDispatch();
22+
const intl = useIntl();
4323
const courseDetails = useModel('courseDetails', courseId);
4424
document.title = getPageHeadTitle(courseDetails?.name, intl.formatMessage(messages.heading));
45-
46-
useEffect(() => {
47-
dispatch(fetchAssets(courseId));
48-
}, [courseId]);
49-
5025
const {
51-
assetIds,
5226
loadingStatus,
5327
addingStatus: addAssetStatus,
5428
deletingStatus: deleteAssetStatus,
5529
updatingStatus: updateAssetStatus,
56-
usageStatus: usagePathStatus,
5730
errors: errorMessages,
5831
} = useSelector(state => state.assets);
5932

60-
const handleErrorReset = (error) => dispatch(resetErrors(error));
61-
const handleDeleteFile = (id) => dispatch(deleteAssetFile(courseId, id));
62-
const handleDownloadFile = (selectedRows) => dispatch(fetchAssetDownload({ selectedRows, courseId }));
63-
const handleAddFile = (files) => {
64-
handleErrorReset({ errorType: 'add' });
65-
dispatch(validateAssetFiles(courseId, files));
66-
};
67-
const handleFileOverwrite = (close, files) => {
68-
Object.values(files).forEach(file => dispatch(addAssetFile(courseId, file, true)));
69-
close();
70-
};
71-
const handleLockFile = (fileId, locked) => {
72-
handleErrorReset({ errorType: 'lock' });
73-
dispatch(updateAssetLock({ courseId, assetId: fileId, locked }));
74-
};
75-
const handleUsagePaths = (asset) => dispatch(getUsagePaths({ asset, courseId }));
76-
const handleFileOrder = ({ newFileIdOrder, sortType }) => {
77-
dispatch(updateAssetOrder(courseId, newFileIdOrder, sortType));
78-
};
79-
80-
const thumbnailPreview = (props) => FileThumbnail(props);
81-
const infoModalSidebar = (asset) => FileInfoModalSidebar({
82-
asset,
83-
handleLockedAsset: handleLockFile,
84-
});
85-
86-
const assets = useModels('assets', assetIds);
87-
const data = {
88-
fileIds: assetIds,
89-
loadingStatus,
90-
usagePathStatus,
91-
usageErrorMessages: errorMessages.usageMetrics,
92-
fileType: 'file',
93-
};
94-
const maxFileSize = 20 * 1048576;
95-
96-
const activeColumn = {
97-
id: 'activeStatus',
98-
Header: intl.formatMessage(messages.fileActiveColumn),
99-
accessor: 'activeStatus',
100-
Cell: ({ row }) => ActiveColumn({ row, pageLoadStatus: loadingStatus }),
101-
Filter: CheckboxFilter,
102-
filter: 'exactTextCase',
103-
filterChoices: [
104-
{ name: intl.formatMessage(messages.activeCheckboxLabel), value: 'active' },
105-
{ name: intl.formatMessage(messages.inactiveCheckboxLabel), value: 'inactive' },
106-
],
107-
};
108-
const accessColumn = {
109-
id: 'lockStatus',
110-
Header: intl.formatMessage(messages.fileAccessColumn),
111-
accessor: 'lockStatus',
112-
Cell: ({ row }) => AccessColumn({ row }),
113-
Filter: CheckboxFilter,
114-
filterChoices: [
115-
{ name: intl.formatMessage(messages.lockedCheckboxLabel), value: 'locked' },
116-
{ name: intl.formatMessage(messages.publicCheckboxLabel), value: 'public' },
117-
],
118-
};
119-
const thumbnailColumn = {
120-
id: 'thumbnail',
121-
Header: '',
122-
Cell: ({ row }) => ThumbnailColumn({ row, thumbnailPreview }),
123-
};
124-
const fileSizeColumn = {
125-
id: 'fileSize',
126-
Header: intl.formatMessage(messages.fileSizeColumn),
127-
accessor: 'fileSize',
128-
Cell: ({ row }) => {
129-
const { fileSize } = row.original;
130-
return getFileSizeToClosestByte(fileSize);
131-
},
132-
};
33+
useEffect(() => {
34+
dispatch(fetchAssets(courseId));
35+
}, [courseId]);
13336

134-
const tableColumns = [
135-
{ ...thumbnailColumn },
136-
{
137-
Header: intl.formatMessage(messages.fileNameColumn),
138-
accessor: 'displayName',
139-
},
140-
{ ...fileSizeColumn },
141-
{
142-
Header: intl.formatMessage(messages.fileTypeColumn),
143-
accessor: 'wrapperType',
144-
Filter: CheckboxFilter,
145-
filter: 'includesValue',
146-
filterChoices: [
147-
{
148-
name: intl.formatMessage(messages.codeCheckboxLabel),
149-
value: 'code',
150-
},
151-
{
152-
name: intl.formatMessage(messages.imageCheckboxLabel),
153-
value: 'image',
154-
},
155-
{
156-
name: intl.formatMessage(messages.documentCheckboxLabel),
157-
value: 'document',
158-
},
159-
{
160-
name: intl.formatMessage(messages.audioCheckboxLabel),
161-
value: 'audio',
162-
},
163-
{
164-
name: intl.formatMessage(messages.otherCheckboxLabel),
165-
value: 'other',
166-
},
167-
],
168-
},
169-
{ ...activeColumn },
170-
{ ...accessColumn },
171-
];
37+
const handleErrorReset = (error) => dispatch(resetErrors(error));
17238

17339
if (loadingStatus === RequestStatus.DENIED) {
17440
return (
@@ -190,30 +56,10 @@ const FilesPage = ({
19056
loadingStatus={loadingStatus}
19157
/>
19258
<div className="h2">
193-
<FormattedMessage {...messages.heading} />
59+
{intl.formatMessage(messages.heading)}
19460
</div>
19561
{loadingStatus !== RequestStatus.FAILED && (
196-
<>
197-
<FileTable
198-
{...{
199-
courseId,
200-
data,
201-
handleAddFile,
202-
handleDeleteFile,
203-
handleDownloadFile,
204-
handleLockFile,
205-
handleUsagePaths,
206-
handleErrorReset,
207-
handleFileOrder,
208-
tableColumns,
209-
maxFileSize,
210-
thumbnailPreview,
211-
infoModalSidebar,
212-
files: assets,
213-
}}
214-
/>
215-
<FileValidationModal {...{ handleFileOverwrite }} />
216-
</>
62+
<CourseFilesSlot courseId={courseId} />
21763
)}
21864
</Container>
21965
</FilesPageProvider>
@@ -222,8 +68,6 @@ const FilesPage = ({
22268

22369
FilesPage.propTypes = {
22470
courseId: PropTypes.string.isRequired,
225-
// injected
226-
intl: intlShape.isRequired,
22771
};
22872

229-
export default injectIntl(FilesPage);
73+
export default FilesPage;

0 commit comments

Comments
 (0)