diff --git a/src/files-and-uploads/FilesAndUploads.jsx b/src/files-and-uploads/FilesAndUploads.jsx
index d2a203de0..97f48cfc9 100644
--- a/src/files-and-uploads/FilesAndUploads.jsx
+++ b/src/files-and-uploads/FilesAndUploads.jsx
@@ -28,7 +28,7 @@ import {
updateAssetOrder,
fetchAssetDownload,
} from './data/thunks';
-import { sortFiles } from './data/utils';
+import { getFileSizeToClosestByte, sortFiles } from './data/utils';
import messages from './messages';
import FileInfo from './FileInfo';
@@ -36,9 +36,9 @@ import FileInput, { useFileInput } from './FileInput';
import FilesAndUploadsProvider from './FilesAndUploadsProvider';
import {
GalleryCard,
- ListCard,
TableActions,
} from './table-components';
+import { AccessColumn, MoreInfoColumn, ThumbnailColumn } from './table-components/table-custom-columns';
import ApiStatusToast from './ApiStatusToast';
import { clearErrors } from './data/slice';
import getPageHeadTitle from '../generic/utils';
@@ -141,34 +141,83 @@ const FilesAndUploads = ({
/>
);
- const fileCard = ({ className, original }) => {
- if (currentView === defaultVal) {
- return (
-
- );
- }
- return (
-
- );
+ const fileCard = ({ className, original }) => (
+
+ );
+
+ const accessColumn = {
+ id: 'locked',
+ Header: 'Access',
+ Cell: ({ row }) => AccessColumn({ row }),
};
+ const thumbnailColumn = {
+ id: 'thumbnail',
+ Header: '',
+ Cell: ({ row }) => ThumbnailColumn({ row }),
+ };
+ const fileSizeColumn = {
+ id: 'fileSize',
+ Header: 'File size',
+ Cell: ({ row }) => {
+ const { fileSize } = row.original;
+ return getFileSizeToClosestByte(fileSize);
+ },
+ };
+ const moreInfoColumn = {
+ id: 'moreInfo',
+ Header: '',
+ Cell: ({ row }) => MoreInfoColumn({
+ row,
+ handleLock: handleLockedAsset,
+ handleBulkDownload,
+ handleOpenAssetInfo,
+ handleOpenDeleteConfirmation,
+ }),
+ };
+
+ const tableColumns = [
+ { ...thumbnailColumn },
+ {
+ Header: 'File name',
+ accessor: 'displayName',
+ },
+ { ...fileSizeColumn },
+ {
+ Header: 'Type',
+ accessor: 'wrapperType',
+ Filter: CheckboxFilter,
+ filter: 'includesValue',
+ filterChoices: [
+ {
+ name: 'Code',
+ value: 'code',
+ },
+ {
+ name: 'Images',
+ value: 'image',
+ },
+ {
+ name: 'Documents',
+ value: 'document',
+ },
+ {
+ name: 'Audio',
+ value: 'audio',
+ },
+ ],
+ },
+ { ...accessColumn },
+ { ...moreInfoColumn },
+ ];
if (loadingStatus === RequestStatus.DENIED) {
return (
@@ -244,36 +293,7 @@ const FilesAndUploads = ({
}}
tableActions={headerActions}
bulkActions={headerActions}
- columns={[
- {
- Header: 'Name',
- accessor: 'displayName',
- },
- {
- Header: 'Type',
- accessor: 'wrapperType',
- Filter: CheckboxFilter,
- filter: 'includesValue',
- filterChoices: [
- {
- name: 'Code',
- value: 'code',
- },
- {
- name: 'Images',
- value: 'image',
- },
- {
- name: 'Documents',
- value: 'document',
- },
- {
- name: 'Audio',
- value: 'audio',
- },
- ],
- },
- ]}
+ columns={tableColumns}
itemCount={totalCount}
pageCount={Math.ceil(totalCount / 50)}
data={assets}
@@ -292,7 +312,7 @@ const FilesAndUploads = ({
{ currentView === 'card' &&
}
- { currentView === 'list' &&
}
+ { currentView === 'list' &&
}
{
expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible();
- expect(screen.queryByTestId('list-card-mOckID1')).toBeNull();
+ expect(screen.queryByRole('table')).toBeNull();
const listButton = screen.getByLabelText('List');
await act(async () => {
@@ -176,7 +176,7 @@ describe('FilesAndUploads', () => {
});
expect(screen.queryByTestId('grid-card-mOckID1')).toBeNull();
- expect(screen.getByTestId('list-card-mOckID1')).toBeVisible();
+ expect(screen.getByRole('table')).toBeVisible();
});
});
diff --git a/src/files-and-uploads/table-components/table-custom-columns/AccessColumn.jsx b/src/files-and-uploads/table-components/table-custom-columns/AccessColumn.jsx
new file mode 100644
index 000000000..b1cde1e03
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/AccessColumn.jsx
@@ -0,0 +1,42 @@
+import React from 'react';
+import { PropTypes } from 'prop-types';
+import { Icon, OverlayTrigger, Tooltip } from '@edx/paragon';
+import { Locked, LockOpen } from '@edx/paragon/icons';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import messages from '../../messages';
+
+const AccessColumn = ({
+ row,
+ // injected
+ intl,
+}) => {
+ const { locked } = row.original;
+ return (
+
+ {intl.formatMessage(messages.lockFileTooltipContent)}
+
+ )}
+ >
+ {locked ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+AccessColumn.propTypes = {
+ row: {
+ original: {
+ locked: PropTypes.bool.isRequired,
+ }.isRequired,
+ }.isRequired,
+ // injected
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(AccessColumn);
diff --git a/src/files-and-uploads/table-components/table-custom-columns/ActiveColumn.jsx b/src/files-and-uploads/table-components/table-custom-columns/ActiveColumn.jsx
new file mode 100644
index 000000000..a604dfe34
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/ActiveColumn.jsx
@@ -0,0 +1,20 @@
+import React from 'react';
+import { PropTypes } from 'prop-types';
+import { Icon } from '@edx/paragon';
+import { Check } from '@edx/paragon/icons';
+
+const ActiveColumn = ({ row }) => {
+ const { usageLocations } = row.original;
+ const numOfUsageLocations = usageLocations.length;
+ return numOfUsageLocations > 0 ? : null;
+};
+
+ActiveColumn.propTypes = {
+ row: {
+ original: {
+ usageLocations: PropTypes.arrayOf(PropTypes.string).isRequired,
+ }.isRequired,
+ }.isRequired,
+};
+
+export default ActiveColumn;
diff --git a/src/files-and-uploads/table-components/table-custom-columns/MoreInfoColumn.jsx b/src/files-and-uploads/table-components/table-custom-columns/MoreInfoColumn.jsx
new file mode 100644
index 000000000..762b553ab
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/MoreInfoColumn.jsx
@@ -0,0 +1,155 @@
+import React, { useState } from 'react';
+import { PropTypes } from 'prop-types';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import {
+ Button,
+ Icon,
+ IconButton,
+ ModalPopup,
+ Menu,
+ MenuItem,
+ useToggle,
+} from '@edx/paragon';
+import { MoreHoriz } from '@edx/paragon/icons';
+
+import messages from '../../messages';
+
+const MoreInfoColumn = ({
+ row,
+ handleLock,
+ handleBulkDownload,
+ handleOpenAssetInfo,
+ handleOpenDeleteConfirmation,
+ // injected
+ intl,
+}) => {
+ const [isOpen, , close, toggle] = useToggle();
+ const [target, setTarget] = useState(null);
+
+ const {
+ externalUrl,
+ locked,
+ portableUrl,
+ id,
+ wrapperType,
+ displayName,
+ } = row.original;
+ return (
+ <>
+
+
+
+
+ >
+ );
+};
+
+MoreInfoColumn.propTypes = {
+ row: {
+ original: {
+ externalUrl: PropTypes.string,
+ locked: PropTypes.bool,
+ portableUrl: PropTypes.string,
+ id: PropTypes.string.isRequired,
+ wrapperType: PropTypes.string,
+ }.isRequired,
+ }.isRequired,
+ handleLock: PropTypes.func.isRequired,
+ handleBulkDownload: PropTypes.func.isRequired,
+ handleOpenAssetInfo: PropTypes.func.isRequired,
+ handleOpenDeleteConfirmation: PropTypes.func.isRequired,
+ // injected
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(MoreInfoColumn);
diff --git a/src/files-and-uploads/table-components/table-custom-columns/StatusColumn.jsx b/src/files-and-uploads/table-components/table-custom-columns/StatusColumn.jsx
new file mode 100644
index 000000000..8773042e1
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/StatusColumn.jsx
@@ -0,0 +1,22 @@
+import React from 'react';
+import { PropTypes } from 'prop-types';
+import { Badge } from '@edx/paragon';
+
+const StatusColumn = ({ row }) => {
+ const { status } = row.original;
+ return (
+
+ {status}
+
+ );
+};
+
+StatusColumn.propTypes = {
+ row: {
+ original: {
+ status: PropTypes.string.isRequired,
+ }.isRequired,
+ }.isRequired,
+};
+
+export default StatusColumn;
diff --git a/src/files-and-uploads/table-components/table-custom-columns/ThumbnailColumn.jsx b/src/files-and-uploads/table-components/table-custom-columns/ThumbnailColumn.jsx
new file mode 100644
index 000000000..cfbbc962f
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/ThumbnailColumn.jsx
@@ -0,0 +1,37 @@
+import React from 'react';
+import { PropTypes } from 'prop-types';
+import { Image, Icon } from '@edx/paragon';
+import { getSrc } from '../../data/utils';
+
+const ThumbnailColumn = ({ row }) => {
+ const {
+ thumbnail,
+ wrapperType,
+ externalUrl,
+ } = row.original;
+
+ const src = getSrc({ thumbnail, wrapperType, externalUrl });
+ return (
+
+ {thumbnail ? (
+
+ ) : (
+
+
+
+ )}
+
+ );
+};
+
+ThumbnailColumn.propTypes = {
+ row: {
+ original: {
+ thumbnail: PropTypes.string,
+ wrapperType: PropTypes.string.isRequired,
+ externalUrl: PropTypes.string,
+ }.isRequired,
+ }.isRequired,
+};
+
+export default ThumbnailColumn;
diff --git a/src/files-and-uploads/table-components/table-custom-columns/index.js b/src/files-and-uploads/table-components/table-custom-columns/index.js
new file mode 100644
index 000000000..78284945f
--- /dev/null
+++ b/src/files-and-uploads/table-components/table-custom-columns/index.js
@@ -0,0 +1,13 @@
+import AccessColumn from './AccessColumn';
+import ActiveColumn from './ActiveColumn';
+import MoreInfoColumn from './MoreInfoColumn';
+import StatusColumn from './StatusColumn';
+import ThumbnailColumn from './ThumbnailColumn';
+
+export {
+ AccessColumn,
+ ActiveColumn,
+ MoreInfoColumn,
+ StatusColumn,
+ ThumbnailColumn,
+};