Skip to content

Commit 72390d9

Browse files
committed
feat: implement file picker mode for files page
1 parent 9dbbf51 commit 72390d9

8 files changed

Lines changed: 109 additions & 37 deletions

File tree

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { CourseAuthoringProvider } from '@src/CourseAuthoringContext';
2+
import { useLocation, useParams } from 'react-router-dom';
3+
import FilesPage from './FilesPage';
4+
5+
export const FilePickerPage = () => {
6+
const { courseId } = useParams<{ courseId: string }>();
7+
const location = useLocation();
8+
const params = new URLSearchParams(location.search);
9+
const filePickerOptions = {
10+
usageKey: params.get('usage_key')!,
11+
multiSelect: params.get('multiSelect') === 'true',
12+
mimeType: params.get('mimeType'),
13+
};
14+
15+
return (
16+
<CourseAuthoringProvider courseId={courseId!}>
17+
<FilesPage filePickerMode filePickerOptions={filePickerOptions} />
18+
</CourseAuthoringProvider>
19+
);
20+
};

src/files-and-videos/files-page/FilesPage.jsx renamed to src/files-and-videos/files-page/FilesPage.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { useIntl } from '@edx/frontend-platform/i18n';
22

33
import { Container } from '@openedx/paragon';
4+
import { DeprecatedReduxState } from '@src/store';
45
import { useEffect } from 'react';
56
import { useDispatch, useSelector } from 'react-redux';
67

@@ -13,11 +14,17 @@ import EditFileAlertsSlot from '@src/plugin-slots/EditFileAlertsSlot';
1314

1415
import { EditFileErrors } from '../generic';
1516
import { fetchAssets, resetErrors } from './data/thunks';
16-
import FilesPageProvider from './FilesPageProvider';
17+
import FilesPageProvider, { FilePickerOptions } from './FilesPageProvider';
1718
import messages from './messages';
1819
import './FilesPage.scss';
1920

20-
const FilesPage = () => {
21+
const FilesPage = ({
22+
filePickerMode = false,
23+
filePickerOptions = undefined,
24+
}: {
25+
filePickerMode?: boolean,
26+
filePickerOptions?: FilePickerOptions,
27+
}) => {
2128
const intl = useIntl();
2229
const dispatch = useDispatch();
2330
const { courseId, courseDetails } = useCourseAuthoringContext();
@@ -28,7 +35,7 @@ const FilesPage = () => {
2835
deletingStatus: deleteAssetStatus,
2936
updatingStatus: updateAssetStatus,
3037
errors: errorMessages,
31-
} = useSelector(state => state.assets);
38+
} = useSelector((state:DeprecatedReduxState) => state.assets);
3239

3340
useEffect(() => {
3441
dispatch(fetchAssets(courseId));
@@ -45,7 +52,7 @@ const FilesPage = () => {
4552
}
4653

4754
return (
48-
<FilesPageProvider courseId={courseId}>
55+
<FilesPageProvider filePickerMode={filePickerMode} filePickerOptions={filePickerOptions}>
4956
<Container size="xl" className="p-4 pt-4.5">
5057
<EditFileErrors
5158
resetErrors={handleErrorReset}

src/files-and-videos/files-page/FilesPageProvider.jsx

Lines changed: 0 additions & 25 deletions
This file was deleted.
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
import React, { useMemo } from 'react';
2+
3+
export interface FilePickerOptions {
4+
usageKey: string,
5+
multiSelect: boolean,
6+
mimeType: string | null,
7+
}
8+
9+
interface FilesPageContextInterface {
10+
filePickerMode: boolean,
11+
filePickerOptions?: FilePickerOptions,
12+
13+
}
14+
15+
export const FilesPageContext = React.createContext<FilesPageContextInterface>({
16+
filePickerMode: false,
17+
});
18+
19+
interface FilesPageProviderProps extends FilesPageContextInterface {
20+
children: React.ReactNode,
21+
}
22+
23+
const FilesPageProvider = ({
24+
children,
25+
filePickerMode = false,
26+
filePickerOptions,
27+
}: FilesPageProviderProps) => {
28+
const contextValue = useMemo(() => ({
29+
filePickerMode,
30+
filePickerOptions,
31+
}), []);
32+
return (
33+
<FilesPageContext.Provider
34+
value={contextValue}
35+
>
36+
{children}
37+
</FilesPageContext.Provider>
38+
);
39+
};
40+
41+
export default FilesPageProvider;

src/files-and-videos/generic/FileTable.jsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,7 @@
1-
import { useCallback, useEffect, useState } from 'react';
1+
import { FilesPageContext } from '@src/files-and-videos/files-page/FilesPageProvider';
2+
import {
3+
useCallback, useContext, useEffect, useState,
4+
} from 'react';
25
import { useSelector } from 'react-redux';
36
import PropTypes from 'prop-types';
47
import isEmpty from 'lodash/isEmpty';
@@ -11,7 +14,7 @@ import {
1114
useToggle,
1215
} from '@openedx/paragon';
1316

14-
import { RequestStatus } from '../../data/constants';
17+
import { RequestStatus } from '@src/data/constants';
1518
import { sortFiles } from './utils';
1619
import messages from './messages';
1720

@@ -78,6 +81,7 @@ const FileTable = ({
7881
} = data;
7982
const defaultCurrentView = (fileType === 'video' && localStorage.getItem('videosCurrentView')) || (fileType === 'file' && localStorage.getItem('filesCurrentView')) || defaultView;
8083
const [currentView, setCurrentView] = useState(defaultCurrentView);
84+
const { filePickerMode, filePickerOptions } = useContext(FilesPageContext);
8185

8286
useEffect(() => {
8387
if (!isEmpty(selectedRows) && Object.keys(selectedRows[0]).length > 0) {
@@ -187,6 +191,7 @@ const FileTable = ({
187191
if (!hasMoreInfoColumn) {
188192
tableColumns.push({ ...moreInfoColumn });
189193
}
194+
const maxSelectedRows = filePickerOptions?.multiSelect === false ? 1 : undefined;
190195

191196
return (
192197
<div className="files-table">
@@ -196,6 +201,7 @@ const FileTable = ({
196201
isSortable
197202
isSelectable
198203
isPaginated
204+
maxSelectedRows={maxSelectedRows}
199205
defaultColumnValues={{ Filter: TextFilter }}
200206
dataViewToggleOptions={{
201207
isDataViewToggleEnabled: true,

src/files-and-videos/generic/table-components/TableActions.jsx

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
import { getConfig } from '@edx/frontend-platform';
22
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
3-
import { Button, DataTableContext, Dropdown, useToggle, } from '@openedx/paragon';
3+
import {
4+
Button, DataTableContext, Dropdown, useToggle,
5+
} from '@openedx/paragon';
46
import { Add, Tune } from '@openedx/paragon/icons';
7+
import FilesPageProvider, { FilesPageContext } from '@src/files-and-videos/files-page/FilesPageProvider';
58
import { isEmpty } from 'lodash';
69
import { PropTypes } from 'prop-types';
710
import React, { useContext, useEffect } from 'react';
@@ -21,15 +24,15 @@ const TableActions = ({
2124
const intl = useIntl();
2225
const [isSortOpen, openSort, closeSort] = useToggle(false);
2326
const { state, clearSelection } = useContext(DataTableContext);
24-
const filePickerParams = new URLSearchParams(window.location.search);
2527

26-
const showFilePicker = Boolean(filePickerParams.get('filePicker')) && Boolean(window.opener);
28+
const { filePickerMode } = useContext(FilesPageContext);
29+
// If window.opener is not available, show the user some error message.
30+
const showFilePicker = filePickerMode; // && Boolean(window.opener);
2731
// This useEffect saves DataTable state so it can persist after table re-renders due to data reload.
2832
useEffect(() => {
2933
setInitialState(state);
3034
}, [state]);
3135

32-
3336
const handleOpenFileSelector = () => {
3437
fileInputControl.click();
3538
clearSelection();

src/index.jsx

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import {
22
APP_INIT_ERROR, APP_READY, subscribe, initialize, mergeConfig, getConfig, getPath,
33
} from '@edx/frontend-platform';
4-
import { AppProvider, ErrorPage } from '@edx/frontend-platform/react';
4+
import { AppProvider, ErrorPage, PageWrap } from '@edx/frontend-platform/react';
5+
import { FilesPage } from '@src/files-and-videos';
6+
import { FilePickerPage } from '@src/files-and-videos/files-page/FilePickerPage';
57
import React, { StrictMode, useEffect } from 'react';
68
import { createRoot } from 'react-dom/client';
79
import {
@@ -93,6 +95,7 @@ const App = () => {
9395
<Route path="/legacy/preview-changes/:usageKey" element={<PreviewChangesEmbed />} />
9496
<Route path="/course/:courseId/*" element={<CourseAuthoringRoutes />} />
9597
<Route path="/course_rerun/:courseId" element={<CourseRerun />} />
98+
<Route path="/file_picker/:courseId" element={<PageWrap><FilePickerPage /></PageWrap>} />
9699
{getConfig().ENABLE_ACCESSIBILITY_PAGE === 'true' && (
97100
<Route path="/accessibility" element={<AccessibilityPage />} />
98101
)}

src/store.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,24 @@ type InferState<ReducerType> = ReducerType extends Reducer<infer T> ? T : never;
3434
export interface DeprecatedReduxState {
3535
customPages: Record<string, any>;
3636
discussions: Record<string, any>;
37-
assets: Record<string, any>;
37+
assets: {
38+
assetIds: string[];
39+
loadingStatus: RequestStatusType;
40+
duplicateFiles: string[];
41+
updatingStatus: string;
42+
addingStatus: string;
43+
deletingStatus: string;
44+
usageStatus: string;
45+
errors: {
46+
add: string[];
47+
delete: string[];
48+
lock: string[];
49+
download: string[];
50+
usageMetrics: string[];
51+
loading:string;
52+
53+
};
54+
};
3855
pagesAndResources: Record<string, any>;
3956
scheduleAndDetails: Record<string, any>;
4057
studioHome: InferState<typeof studioHomeReducer>;

0 commit comments

Comments
 (0)