Skip to content
Merged
Show file tree
Hide file tree
Changes from 17 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
2 changes: 2 additions & 0 deletions plugins/course-apps/proctoring/Settings.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ describe('ProctoredExamSettings', () => {
provider: null,
});

axiosMock.onGet(/course_index/).reply(200, { sections: [] });

axiosMock.onGet(
StudioApiService.getProctoredExamSettingsUrl(defaultProps.courseId),
).reply(200, {
Expand Down
54 changes: 5 additions & 49 deletions src/CourseAuthoringContext.tsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
import { getConfig } from '@edx/frontend-platform';
import {
createContext, useContext, useMemo, useState,
createContext, useContext, useMemo,
} from 'react';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useCreateCourseBlock } from '@src/course-outline/data/apiHooks';
import { useSelector } from 'react-redux';
import { useNavigate } from 'react-router';
import { getOutlineIndexData } from '@src/course-outline/data/selectors';
import { useToggleWithValue } from '@src/hooks';
import { SelectionState, type UnitXBlock, type XBlock } from '@src/data/types';
import { type UnitXBlock, type XBlock } from '@src/data/types';
import { CourseDetailsData } from './data/api';
import { useCourseDetails, useWaffleFlags } from './data/apiHooks';
import { RequestStatusType } from './data/constants';
import { getOutlineIndexData } from './course-outline/data/selectors';

type ModalState = {
export type ModalState = {
value?: XBlock | UnitXBlock;
subsectionId?: string;
sectionId?: string;
Expand All @@ -26,20 +25,12 @@ export type CourseAuthoringContextData = {
courseDetails?: CourseDetailsData;
courseDetailStatus: RequestStatusType;
canChangeProviders: boolean;
handleAddAndOpenUnit: ReturnType<typeof useCreateCourseBlock>;
handleAddBlock: ReturnType<typeof useCreateCourseBlock>;
openUnitPage: (locator: string) => void;
openUnitPage: (locator: string) => Promise<void>;
getUnitUrl: (locator: string) => string;
isUnlinkModalOpen: boolean;
currentUnlinkModalData?: ModalState;
openUnlinkModal: (value: ModalState) => void;
closeUnlinkModal: () => void;
isPublishModalOpen: boolean;
currentPublishModalData?: ModalState;
openPublishModal: (value: ModalState) => void;
closePublishModal: () => void;
currentSelection?: SelectionState;
setCurrentSelection: React.Dispatch<React.SetStateAction<SelectionState | undefined>>;
};

/**
Expand Down Expand Up @@ -72,20 +63,6 @@ export const CourseAuthoringProvider = ({
openUnlinkModal,
closeUnlinkModal,
] = useToggleWithValue<ModalState>();
const [
isPublishModalOpen,
currentPublishModalData,
openPublishModal,
closePublishModal,
] = useToggleWithValue<ModalState>();
/**
* This will hold the state of current item that is being operated on,
* For example:
* - the details of container that is being edited.
* - the details of container of which see more dropdown is open.
* It is mostly used in modals which should be soon be replaced with its equivalent in sidebar.
*/
const [currentSelection, setCurrentSelection] = useState<SelectionState | undefined>();

const getUnitUrl = (locator: string) => {
if (getConfig().ENABLE_UNIT_PAGE === 'true' && waffleFlags.useNewUnitPage) {
Expand All @@ -107,52 +84,31 @@ export const CourseAuthoringProvider = ({
window.location.assign(url);
}
};
/**
* import a unit block from library and redirect user to this unit page.
*/
const handleAddAndOpenUnit = useCreateCourseBlock(courseId, openUnitPage);
const handleAddBlock = useCreateCourseBlock(courseId);

const context = useMemo<CourseAuthoringContextData>(() => ({
courseId,
courseUsageKey,
courseDetails,
courseDetailStatus,
canChangeProviders,
handleAddBlock,
handleAddAndOpenUnit,
getUnitUrl,
openUnitPage,
isUnlinkModalOpen,
openUnlinkModal,
closeUnlinkModal,
currentUnlinkModalData,
isPublishModalOpen,
currentPublishModalData,
openPublishModal,
closePublishModal,
currentSelection,
setCurrentSelection,
}), [
courseId,
courseUsageKey,
courseDetails,
courseDetailStatus,
canChangeProviders,
handleAddBlock,
handleAddAndOpenUnit,
getUnitUrl,
openUnitPage,
isUnlinkModalOpen,
openUnlinkModal,
closeUnlinkModal,
currentUnlinkModalData,
isPublishModalOpen,
currentPublishModalData,
openPublishModal,
closePublishModal,
currentSelection,
setCurrentSelection,
]);

return (
Expand Down
13 changes: 8 additions & 5 deletions src/CourseAuthoringRoutes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
OutlineSidebarProvider,
OutlineSidebarPagesProvider,
} from './course-outline';
import { CourseOutlineProvider } from './course-outline/CourseOutlineContext';
import ScheduleAndDetails from './schedule-and-details';
import { GradingSettings } from './grading-settings';
import CourseTeam from './course-team/CourseTeam';
Expand Down Expand Up @@ -66,11 +67,13 @@ const CourseAuthoringRoutes = () => {
path="/"
element={(
<PageWrap>
<OutlineSidebarPagesProvider>
<OutlineSidebarProvider>
<CourseOutline />
</OutlineSidebarProvider>
</OutlineSidebarPagesProvider>
<CourseOutlineProvider>
<OutlineSidebarPagesProvider>
<OutlineSidebarProvider>
<CourseOutline />
</OutlineSidebarProvider>
</OutlineSidebarPagesProvider>
</CourseOutlineProvider>
</PageWrap>
)}
/>
Expand Down
2 changes: 1 addition & 1 deletion src/content-tags-drawer/data/apiHooks.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ describe('useTaxonomyTagsData', () => {
// Assert that useQueries was called with the correct arguments
expect(useQueries).toHaveBeenCalledWith({
queries: [
{ queryKey: ['taxonomyTags', taxonomyId, null, 1, ''], queryFn: expect.any(Function), staleTime: Infinity },
{ queryKey: ['contentTags', 'taxonomyTags', taxonomyId, null, 1, ''], queryFn: expect.any(Function), staleTime: Infinity },
],
});

Expand Down
39 changes: 33 additions & 6 deletions src/content-tags-drawer/data/apiHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,33 @@ import { libraryAuthoringQueryKeys, libraryQueryPredicate, xblockQueryKeys } fro
import { getLibraryId } from '../../generic/key-utils';
import type { UpdateTagsData } from './types';

export const contentTagsQueryKeys = {
all: ['contentTags'],
taxonomyTags: (taxonomyId: number, parentTag: string | null, page: number, searchTerm: string) => [
...contentTagsQueryKeys.all,
'taxonomyTags',
taxonomyId,
parentTag,
page,
searchTerm,
],
contentTaxonomyTags: (contentId: string) => [
...contentTagsQueryKeys.all,
'contentTaxonomyTags',
contentId,
],
contentData: (contentId?: string) => [
...contentTagsQueryKeys.all,
'contentData',
contentId,
],
contentTagsCount: (contentPattern: string) => [
...contentTagsQueryKeys.all,
'contentTagsCount',
contentPattern,
],
};

/**
* Builds the query to get the taxonomy tags
*/
Expand All @@ -43,7 +70,7 @@ export const useTaxonomyTagsData = (
const queries: { queryKey: any[]; queryFn: typeof queryFn; staleTime: number }[] = [];
for (let page = 1; page <= numPages; page++) {
queries.push(
{ queryKey: ['taxonomyTags', taxonomyId, parentTag, page, searchTerm], queryFn, staleTime: Infinity },
{ queryKey: contentTagsQueryKeys.taxonomyTags(taxonomyId, parentTag, page, searchTerm), queryFn, staleTime: Infinity },
);
}

Expand Down Expand Up @@ -74,7 +101,7 @@ export const useTaxonomyTagsData = (

// Store the pre-loaded descendants into the query cache:
preLoadedData.forEach((tags, parentValue) => {
const queryKey = ['taxonomyTags', taxonomyId, parentValue, 1, searchTerm];
const queryKey = contentTagsQueryKeys.taxonomyTags(taxonomyId, parentValue, 1, searchTerm);
const cachedData: TagListData = {
next: '',
previous: '',
Expand Down Expand Up @@ -106,7 +133,7 @@ export const useTaxonomyTagsData = (
*/
export const useContentTaxonomyTagsData = (contentId: string) => (
useQuery({
queryKey: ['contentTaxonomyTags', contentId],
queryKey: contentTagsQueryKeys.contentTaxonomyTags(contentId),
queryFn: () => getContentTaxonomyTagsData(contentId),
})
);
Expand All @@ -118,7 +145,7 @@ export const useContentTaxonomyTagsData = (contentId: string) => (
*/
export const useContentData = (contentId?: string, enabled: boolean = true) => (
useQuery({
queryKey: ['contentData', contentId],
queryKey: contentTagsQueryKeys.contentData(contentId),
queryFn: (enabled && contentId) ? () => getContentData(contentId) : skipToken,
})
);
Expand All @@ -137,15 +164,15 @@ export const useContentTaxonomyTagsUpdater = (contentId: string) => {
updateContentTaxonomyTags(contentId, tagsData)
),
onSettled: () => {
queryClient.invalidateQueries({ queryKey: ['contentTaxonomyTags', contentId] });
queryClient.invalidateQueries({ queryKey: contentTagsQueryKeys.contentTaxonomyTags(contentId) });
/// Invalidate query with pattern on course outline
let contentPattern;
if (contentId.includes('course-v1')) {
contentPattern = contentId;
} else {
contentPattern = contentId.replace(/\+type@.*$/, '*');
}
queryClient.invalidateQueries({ queryKey: ['contentTagsCount', contentPattern] });
queryClient.invalidateQueries({ queryKey: contentTagsQueryKeys.contentTagsCount(contentPattern) });
if (contentId.startsWith('lb:') || contentId.startsWith('lib-collection:') || contentId.startsWith('lct:')) {
// Obtain library id from contentId
const libraryId = getLibraryId(contentId);
Expand Down
13 changes: 8 additions & 5 deletions src/course-outline/CourseOutline.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
} from '@src/testUtils';
import { XBlock } from '@src/data/types';
import { userEvent } from '@testing-library/user-event';
import { CourseOutlineProvider } from './CourseOutlineContext';
import { OutlineSidebarProvider } from './outline-sidebar/OutlineSidebarContext';
import { OutlineSidebarPagesProvider } from './outline-sidebar/OutlineSidebarPagesContext';
import {
Expand Down Expand Up @@ -144,11 +145,13 @@ const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));

const renderComponent = () => render(
<CourseAuthoringProvider courseId={courseId}>
<OutlineSidebarPagesProvider>
<OutlineSidebarProvider>
<CourseOutline />
</OutlineSidebarProvider>
</OutlineSidebarPagesProvider>
<CourseOutlineProvider>
<OutlineSidebarPagesProvider>
<OutlineSidebarProvider>
<CourseOutline />
</OutlineSidebarProvider>
</OutlineSidebarPagesProvider>
</CourseOutlineProvider>
</CourseAuthoringProvider>,
);

Expand Down
Loading