feat: update usage location call (#764)
This commit is contained in:
@@ -1,11 +1,30 @@
|
||||
import React from 'react';
|
||||
import { PropTypes } from 'prop-types';
|
||||
import { Icon } from '@edx/paragon';
|
||||
import { isNil } from 'lodash';
|
||||
import { injectIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
|
||||
import { Icon, Spinner } from '@edx/paragon';
|
||||
import { Check } from '@edx/paragon/icons';
|
||||
|
||||
const ActiveColumn = ({ row }) => {
|
||||
const { usageLocations } = row.original;
|
||||
const numOfUsageLocations = usageLocations?.length;
|
||||
if (isNil(usageLocations)) {
|
||||
return (
|
||||
<Spinner
|
||||
animation="border"
|
||||
role="status"
|
||||
variant="primary"
|
||||
size="sm"
|
||||
screenReaderText={(
|
||||
<FormattedMessage
|
||||
id="authoring.loading"
|
||||
defaultMessage="Loading..."
|
||||
description="Screen-reader message for when a page is loading."
|
||||
/>
|
||||
)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
const numOfUsageLocations = usageLocations.length;
|
||||
return numOfUsageLocations > 0 ? <Icon src={Check} /> : null;
|
||||
};
|
||||
|
||||
@@ -17,4 +36,4 @@ ActiveColumn.propTypes = {
|
||||
}.isRequired,
|
||||
};
|
||||
|
||||
export default ActiveColumn;
|
||||
export default injectIntl(ActiveColumn);
|
||||
|
||||
@@ -80,7 +80,7 @@ const VideosPage = ({
|
||||
|
||||
const supportedFileFormats = { 'video/*': videoSupportedFileFormats || FILES_AND_UPLOAD_TYPE_FILTERS.video };
|
||||
|
||||
const handleAddFile = (file) => dispatch(addVideoFile(courseId, file));
|
||||
const handleAddFile = (file) => dispatch(addVideoFile(courseId, file, videoIds));
|
||||
const handleDeleteFile = (id) => dispatch(deleteVideoFile(courseId, id));
|
||||
const handleDownloadFile = (selectedRows) => dispatch(fetchVideoDownload({ selectedRows, courseId }));
|
||||
const handleUsagePaths = (video) => dispatch(getUsagePaths({ video, courseId }));
|
||||
|
||||
@@ -59,7 +59,13 @@ const mockStore = async (
|
||||
status,
|
||||
) => {
|
||||
const fetchVideosUrl = getVideosUrl(courseId);
|
||||
axiosMock.onGet(fetchVideosUrl).reply(getStatusValue(status), generateFetchVideosApiResponse());
|
||||
const videosData = generateFetchVideosApiResponse();
|
||||
axiosMock.onGet(fetchVideosUrl).reply(getStatusValue(status), videosData);
|
||||
|
||||
videosData.previous_uploads.forEach((video) => {
|
||||
axiosMock.onGet(`${getVideosUrl(courseId)}/${video.edx_video_id}/usage`).reply(200, { usageLocations: [] });
|
||||
});
|
||||
|
||||
renderComponent();
|
||||
await executeThunk(fetchVideos(courseId), store.dispatch);
|
||||
};
|
||||
@@ -71,7 +77,7 @@ const emptyMockStore = async (status) => {
|
||||
await executeThunk(fetchVideos(courseId), store.dispatch);
|
||||
};
|
||||
|
||||
describe('FilesAndUploads', () => {
|
||||
describe('Videos page', () => {
|
||||
describe('empty state', () => {
|
||||
beforeEach(async () => {
|
||||
initializeMockApp({
|
||||
@@ -179,6 +185,13 @@ describe('FilesAndUploads', () => {
|
||||
|
||||
it('should switch table to list view', async () => {
|
||||
await mockStore(RequestStatus.SUCCESSFUL);
|
||||
axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1/usage`)
|
||||
.reply(201, {
|
||||
usageLocations: [{
|
||||
display_location: 'subsection - unit / block',
|
||||
url: 'base/unit_id#block_id',
|
||||
}],
|
||||
});
|
||||
expect(screen.getByTestId('files-data-table')).toBeVisible();
|
||||
|
||||
expect(screen.getByTestId('grid-card-mOckID1')).toBeVisible();
|
||||
@@ -219,9 +232,10 @@ describe('FilesAndUploads', () => {
|
||||
axiosMock.onGet(getCourseVideosApiUrl(courseId)).reply(200, generateAddVideoApiResponse());
|
||||
|
||||
const addFilesButton = screen.getAllByLabelText('file-input')[3];
|
||||
const { videoIds } = store.getState().videos;
|
||||
await act(async () => {
|
||||
userEvent.upload(addFilesButton, file);
|
||||
await executeThunk(addVideoFile(courseId, file), store.dispatch);
|
||||
await executeThunk(addVideoFile(courseId, file, videoIds), store.dispatch);
|
||||
});
|
||||
const addStatus = store.getState().videos.addingStatus;
|
||||
expect(addStatus).toEqual(RequestStatus.SUCCESSFUL);
|
||||
@@ -419,12 +433,13 @@ describe('FilesAndUploads', () => {
|
||||
const videoMenuButton = screen.getByTestId('file-menu-dropdown-mOckID1');
|
||||
|
||||
axiosMock.onGet(`${getVideosUrl(courseId)}/mOckID1/usage`)
|
||||
.reply(201, {
|
||||
.reply(200, {
|
||||
usageLocations: [{
|
||||
display_location: 'subsection - unit / block',
|
||||
url: 'base/unit_id#block_id',
|
||||
}],
|
||||
});
|
||||
|
||||
await waitFor(() => {
|
||||
fireEvent.click(within(videoMenuButton).getByLabelText('file-menu-toggle'));
|
||||
fireEvent.click(screen.getByText('Info'));
|
||||
|
||||
@@ -177,6 +177,7 @@ export async function uploadVideo(
|
||||
const formData = new FormData();
|
||||
formData.append('uploaded-file', uploadFile);
|
||||
const uploadErrors = [];
|
||||
|
||||
await fetch(uploadUrl, {
|
||||
method: 'PUT',
|
||||
body: formData,
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
addModels,
|
||||
removeModel,
|
||||
updateModel,
|
||||
updateModels,
|
||||
} from '../../../generic/model-store';
|
||||
import {
|
||||
addThumbnail,
|
||||
@@ -38,6 +37,20 @@ import {
|
||||
|
||||
import { updateFileValues } from './utils';
|
||||
|
||||
async function fetchUsageLocation(videoId, dispatch, courseId) {
|
||||
const { usageLocations } = await getVideoUsagePaths({ videoId, courseId });
|
||||
const activeStatus = usageLocations?.length > 0 ? 'active' : 'inactive';
|
||||
|
||||
dispatch(updateModel({
|
||||
modelType: 'videos',
|
||||
model: {
|
||||
id: videoId,
|
||||
usageLocations,
|
||||
activeStatus,
|
||||
},
|
||||
}));
|
||||
}
|
||||
|
||||
export function fetchVideos(courseId) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateLoadingStatus({ courseId, status: RequestStatus.IN_PROGRESS }));
|
||||
@@ -51,6 +64,9 @@ export function fetchVideos(courseId) {
|
||||
}));
|
||||
dispatch(setPageSettings({ ...data }));
|
||||
dispatch(updateLoadingStatus({ courseId, status: RequestStatus.SUCCESSFUL }));
|
||||
parsedVideos.forEach(async (video) => {
|
||||
fetchUsageLocation(video.id, dispatch, courseId);
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.response && error.response.status === 403) {
|
||||
dispatch(updateLoadingStatus({ status: RequestStatus.DENIED }));
|
||||
@@ -90,7 +106,7 @@ export function deleteVideoFile(courseId, id) {
|
||||
};
|
||||
}
|
||||
|
||||
export function addVideoFile(courseId, file) {
|
||||
export function addVideoFile(courseId, file, videoIds) {
|
||||
return async (dispatch) => {
|
||||
dispatch(updateEditStatus({ editType: 'add', status: RequestStatus.IN_PROGRESS }));
|
||||
|
||||
@@ -104,8 +120,9 @@ export function addVideoFile(courseId, file) {
|
||||
edxVideoId,
|
||||
);
|
||||
const { videos } = await fetchVideoList(courseId);
|
||||
const parsedVideos = updateFileValues(videos);
|
||||
dispatch(updateModels({
|
||||
const newVideos = videos.filter(video => !videoIds.includes(video.edxVideoId));
|
||||
const parsedVideos = updateFileValues(newVideos, true);
|
||||
dispatch(addModels({
|
||||
modelType: 'videos',
|
||||
models: parsedVideos,
|
||||
}));
|
||||
|
||||
@@ -15,7 +15,7 @@ ensureConfig([
|
||||
'STUDIO_BASE_URL',
|
||||
], 'Course Apps API service');
|
||||
|
||||
export const updateFileValues = (files) => {
|
||||
export const updateFileValues = (files, isNewFile) => {
|
||||
const updatedFiles = [];
|
||||
files.forEach(file => {
|
||||
const {
|
||||
@@ -25,7 +25,6 @@ export const updateFileValues = (files) => {
|
||||
courseVideoImageUrl,
|
||||
status,
|
||||
transcripts,
|
||||
usageLocations,
|
||||
} = file;
|
||||
const wrapperType = 'video';
|
||||
|
||||
@@ -34,7 +33,6 @@ export const updateFileValues = (files) => {
|
||||
thumbnail = `${getConfig().STUDIO_BASE_URL}${thumbnail}`;
|
||||
}
|
||||
const transcriptStatus = transcripts?.length > 0 ? 'transcribed' : 'notTranscribed';
|
||||
const activeStatus = usageLocations?.length > 0 ? 'active' : 'inactive';
|
||||
|
||||
let uploadStatus = status;
|
||||
if (VIDEO_SUCCESS_STATUSES.includes(status)) {
|
||||
@@ -49,10 +47,11 @@ export const updateFileValues = (files) => {
|
||||
id: edxVideoId,
|
||||
wrapperType,
|
||||
dateAdded: created.toString(),
|
||||
usageLocations: isNewFile ? [] : null,
|
||||
status: uploadStatus,
|
||||
thumbnail,
|
||||
transcriptStatus,
|
||||
activeStatus,
|
||||
activeStatus: 'inactive',
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -43,7 +43,8 @@ describe('<PacingSection />', () => {
|
||||
});
|
||||
|
||||
it('shows disabled radio inputs correctly', () => {
|
||||
const pastDate = '2024-12-31';
|
||||
const year = new Date().getFullYear() + 1;
|
||||
const pastDate = `${year}-12-31`;
|
||||
const initialProps = { ...props, startDate: pastDate };
|
||||
const { getAllByRole, queryAllByText } = render(
|
||||
<RootWrapper {...initialProps} />,
|
||||
|
||||
Reference in New Issue
Block a user