Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 15 additions & 13 deletions src/course-outline/page-alerts/PageAlerts.jsx
Original file line number Diff line number Diff line change
@@ -1,30 +1,31 @@
import React, { useState } from 'react';
import PropTypes from 'prop-types';
import { uniqBy } from 'lodash';
import { getConfig } from '@edx/frontend-platform';
import { useDispatch, useSelector } from 'react-redux';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import {
Alert, Button, Hyperlink, Truncate,
} from '@openedx/paragon';
import {
Campaign as CampaignIcon,
Error as ErrorIcon,
InfoOutline as InfoOutlineIcon,
Warning as WarningIcon,
Error as ErrorIcon,
} from '@openedx/paragon/icons';
import {
Alert, Button, Hyperlink, Truncate,
} from '@openedx/paragon';
import { uniqBy } from 'lodash';
import PropTypes from 'prop-types';
import React, { useState } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { Link, useNavigate } from 'react-router-dom';
import CourseOutlinePageAlertsSlot from '../../plugin-slots/CourseOutlinePageAlertsSlot';
import advancedSettingsMessages from '../../advanced-settings/messages';
import { OutOfSyncAlert } from '../../course-libraries/OutOfSyncAlert';
import { RequestStatus } from '../../data/constants';

import ErrorAlert from '../../editors/sharedComponents/ErrorAlerts/ErrorAlert';
import { RequestStatus } from '../../data/constants';
import AlertMessage from '../../generic/alert-message';
import AlertProctoringError from '../../generic/AlertProctoringError';
import messages from './messages';
import advancedSettingsMessages from '../../advanced-settings/messages';
import { API_ERROR_TYPES } from '../constants';
import { getPasteFileNotices } from '../data/selectors';
import { dismissError, removePasteFileNotices } from '../data/slice';
import { API_ERROR_TYPES } from '../constants';
import { OutOfSyncAlert } from '../../course-libraries/OutOfSyncAlert';
import messages from './messages';

const PageAlerts = ({
courseId,
Expand Down Expand Up @@ -437,6 +438,7 @@ const PageAlerts = ({
{conflictingFilesPasteAlert()}
{newFilesPasteAlert()}
{renderOutOfSyncAlert()}
<CourseOutlinePageAlertsSlot />
</>
);
};
Expand Down
183 changes: 183 additions & 0 deletions src/files-and-videos/files-page/CourseFilesTable.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,183 @@
import { useIntl } from '@edx/frontend-platform/i18n';
import { CheckboxFilter } from '@openedx/paragon';
import {
addAssetFile,
deleteAssetFile,
fetchAssetDownload,
getUsagePaths,
resetErrors,
updateAssetLock,
updateAssetOrder,
validateAssetFiles,
} from '@src/files-and-videos/files-page/data/thunks';
import FileInfoModalSidebar from '@src/files-and-videos/files-page/FileInfoModalSidebar';
import FileThumbnail from '@src/files-and-videos/files-page/FileThumbnail';
import FileValidationModal from '@src/files-and-videos/files-page/FileValidationModal';
import messages from '@src/files-and-videos/files-page/messages';
import {
AccessColumn,
ActiveColumn,
FileTable,
ThumbnailColumn,
} from '@src/files-and-videos/generic';
import { useModels } from '@src/generic/model-store';
import { DeprecatedReduxState } from '@src/store';
import { getFileSizeToClosestByte } from '@src/utils';
import React from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useParams } from 'react-router-dom';

export const CourseFilesTable = () => {
const intl = useIntl();
const { courseId } = useParams() as { courseId: string };
const dispatch = useDispatch();
const {
assetIds,
loadingStatus,
usageStatus: usagePathStatus,
errors: errorMessages,
} = useSelector((state: DeprecatedReduxState) => state.assets);

const handleErrorReset = (error) => dispatch(resetErrors(error));
const handleDeleteFile = (id) => dispatch(deleteAssetFile(courseId, id));
const handleDownloadFile = (selectedRows) => dispatch(fetchAssetDownload({
selectedRows,
courseId,
}));
const handleAddFile = (files) => {
handleErrorReset({ errorType: 'add' });
dispatch(validateAssetFiles(courseId, files));
};
const handleFileOverwrite = (close, files) => {
Object.values(files).forEach(file => dispatch(addAssetFile(courseId, file, true)));
close();
};
const handleLockFile = (fileId, locked) => {
handleErrorReset({ errorType: 'lock' });
dispatch(updateAssetLock({ courseId, assetId: fileId, locked }));
};
const handleUsagePaths = (asset) => dispatch(getUsagePaths({ asset, courseId }));
const handleFileOrder = ({ newFileIdOrder }) => {
dispatch(updateAssetOrder(courseId, newFileIdOrder));
};

const thumbnailPreview = (props) => FileThumbnail(props);
const infoModalSidebar = (asset) => FileInfoModalSidebar({
asset,
handleLockedAsset: handleLockFile,
});

const assets = useModels('assets', assetIds);
const data = {
fileIds: assetIds,
loadingStatus,
usagePathStatus,
usageErrorMessages: errorMessages.usageMetrics,
fileType: 'file',
};
const maxFileSize = 20 * 1048576;

const activeColumn = {
id: 'activeStatus',
Header: intl.formatMessage(messages.fileActiveColumn),
accessor: 'activeStatus',
Cell: ({ row }) => ActiveColumn({ row, pageLoadStatus: loadingStatus }),
Filter: CheckboxFilter,
filter: 'exactTextCase',
filterChoices: [
{ name: intl.formatMessage(messages.activeCheckboxLabel), value: 'active' },
{ name: intl.formatMessage(messages.inactiveCheckboxLabel), value: 'inactive' },
],
};
const accessColumn = {
id: 'lockStatus',
Header: intl.formatMessage(messages.fileAccessColumn),
accessor: 'lockStatus',
Cell: ({ row }) => AccessColumn({ row }),
Filter: CheckboxFilter,
filterChoices: [
{ name: intl.formatMessage(messages.lockedCheckboxLabel), value: 'locked' },
{ name: intl.formatMessage(messages.publicCheckboxLabel), value: 'public' },
],
};
const thumbnailColumn = {
id: 'thumbnail',
Header: '',
Cell: ({ row }) => ThumbnailColumn({ row, thumbnailPreview }),
};
const fileSizeColumn = {
id: 'fileSize',
Header: intl.formatMessage(messages.fileSizeColumn),
accessor: 'fileSize',
Cell: ({ row }) => {
const { fileSize } = row.original;
return getFileSizeToClosestByte(fileSize);
},
};

const tableColumns = [
{ ...thumbnailColumn },
{
Header: intl.formatMessage(messages.fileNameColumn),
accessor: 'displayName',
},
{ ...fileSizeColumn },
{
Header: intl.formatMessage(messages.fileTypeColumn),
accessor: 'wrapperType',
Filter: CheckboxFilter,
filter: 'includesValue',
filterChoices: [
{
name: intl.formatMessage(messages.codeCheckboxLabel),
value: 'code',
},
{
name: intl.formatMessage(messages.imageCheckboxLabel),
value: 'image',
},
{
name: intl.formatMessage(messages.documentCheckboxLabel),
value: 'document',
},
{
name: intl.formatMessage(messages.audioCheckboxLabel),
value: 'audio',
},
{
name: intl.formatMessage(messages.otherCheckboxLabel),
value: 'other',
},
],
},
{ ...activeColumn },
{ ...accessColumn },
];

if (!courseId) {
return null;
}
return (
<>
<FileTable
{...{
courseId,
data,
handleAddFile,
handleDeleteFile,
handleDownloadFile,
handleLockFile,
handleUsagePaths,
handleErrorReset,
handleFileOrder,
tableColumns,
maxFileSize,
thumbnailPreview,
infoModalSidebar,
files: assets,
}}
/>
<FileValidationModal {...{ handleFileOverwrite }} />
</>
);
};
Loading