Skip to content
4 changes: 2 additions & 2 deletions src/course-outline/CourseOutline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,12 @@ import HighlightsModal from './highlights-modal/HighlightsModal';
import EmptyPlaceholder from './empty-placeholder/EmptyPlaceholder';
import PublishModal from './publish-modal/PublishModal';
import PageAlerts from './page-alerts/PageAlerts';
import DraggableList from '../generic/drag-helper/DraggableList';
import DraggableList from './drag-helper/DraggableList';
import {
canMoveSection,
possibleUnitMoves,
possibleSubsectionMoves,
} from '../generic/drag-helper/utils';
} from './drag-helper/utils';
import { useCourseOutline } from './hooks';
import messages from './messages';
import { getTagsExportFile } from './data/api';
Expand Down
1 change: 1 addition & 0 deletions src/course-outline/CourseOutline.scss
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@
@import "./highlights-modal/HighlightsModal";
@import "./publish-modal/PublishModal";
@import "./xblock-status/XBlockStatus";
@import "./drag-helper/SortableItem";
2 changes: 1 addition & 1 deletion src/course-outline/CourseOutline.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ import {
moveUnitOver,
moveSubsection,
moveUnit,
} from '../generic/drag-helper/utils';
} from './drag-helper/utils';

let axiosMock;
let store;
Expand Down
4 changes: 2 additions & 2 deletions src/course-outline/section-card/SectionCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,8 @@ import classNames from 'classnames';
import { setCurrentItem, setCurrentSection } from '../data/slice';
import { RequestStatus } from '../../data/constants';
import CardHeader from '../card-header/CardHeader';
import SortableItem from '../../generic/drag-helper/SortableItem';
import { DragContext } from '../../generic/drag-helper/DragContextProvider';
import SortableItem from '../drag-helper/SortableItem';
import { DragContext } from '../drag-helper/DragContextProvider';
import TitleButton from '../card-header/TitleButton';
import XBlockStatus from '../xblock-status/XBlockStatus';
import { getItemStatus, getItemStatusBorder, scrollToElement } from '../utils';
Expand Down
4 changes: 2 additions & 2 deletions src/course-outline/subsection-card/SubsectionCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,8 @@ import CourseOutlineSubsectionCardExtraActionsSlot from '../../plugin-slots/Cour
import { setCurrentItem, setCurrentSection, setCurrentSubsection } from '../data/slice';
import { RequestStatus } from '../../data/constants';
import CardHeader from '../card-header/CardHeader';
import SortableItem from '../../generic/drag-helper/SortableItem';
import { DragContext } from '../../generic/drag-helper/DragContextProvider';
import SortableItem from '../drag-helper/SortableItem';
import { DragContext } from '../drag-helper/DragContextProvider';
import { useClipboard, PasteComponent } from '../../generic/clipboard';
import TitleButton from '../card-header/TitleButton';
import XBlockStatus from '../xblock-status/XBlockStatus';
Expand Down
2 changes: 1 addition & 1 deletion src/course-outline/unit-card/UnitCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import CourseOutlineUnitCardExtraActionsSlot from '../../plugin-slots/CourseOutl
import { setCurrentItem, setCurrentSection, setCurrentSubsection } from '../data/slice';
import { RequestStatus } from '../../data/constants';
import CardHeader from '../card-header/CardHeader';
import SortableItem from '../../generic/drag-helper/SortableItem';
import SortableItem from '../drag-helper/SortableItem';
import TitleLink from '../card-header/TitleLink';
import XBlockStatus from '../xblock-status/XBlockStatus';
import { getItemStatus, getItemStatusBorder, scrollToElement } from '../utils';
Expand Down
2 changes: 1 addition & 1 deletion src/custom-pages/CustomPages.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import {
} from '@openedx/paragon';
import { Add, SpinnerSimple } from '@openedx/paragon/icons';
import Placeholder from '../editors/Placeholder';
import DraggableList, { SortableItem } from '../editors/sharedComponents/DraggableList';
import DraggableList, { SortableItem } from '../generic/DraggableList';
import ErrorAlert from '../editors/sharedComponents/ErrorAlerts/ErrorAlert';

import { RequestStatus } from '../data/constants';
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import React from 'react';
import React, { useCallback } from 'react';
import PropTypes from 'prop-types';
import { createPortal } from 'react-dom';

import {
DndContext,
Expand All @@ -8,6 +9,7 @@
PointerSensor,
useSensor,
useSensors,
DragOverlay,
} from '@dnd-kit/core';
import {
arrayMove,
Expand All @@ -22,6 +24,9 @@
setState,
updateOrder,
children,
renderOverlay,
activeId,
setActiveId,
}) => {
const sensors = useSensors(
useSensor(PointerSensor),
Expand All @@ -30,7 +35,7 @@
}),
);

const handleDragEnd = (event) => {
const handleDragEnd = useCallback((event) => {
const { active, over } = event;
if (active.id !== over.id) {
let updatedArray;
Expand All @@ -44,13 +49,19 @@
});
updateOrder()(updatedArray);
}
};
setActiveId?.(null);
}, [updateOrder, setActiveId]);

const handleDragStart = useCallback((event) => {
setActiveId?.(event.active.id);
}, [setActiveId]);

return (
<DndContext
sensors={sensors}
modifiers={[restrictToVerticalAxis]}
collisionDetection={closestCenter}
onDragStart={handleDragStart}
onDragEnd={handleDragEnd}
>
<SortableContext
Expand All @@ -59,17 +70,32 @@
>
{children}
</SortableContext>
{renderOverlay && createPortal(
<DragOverlay>
{renderOverlay(activeId)}
</DragOverlay>,
document.body,
)}
</DndContext>
);
};

DraggableList.defaultProps = {
renderOverlay: undefined,
activeId: null,
setActiveId: () => {},

Check warning on line 86 in src/generic/DraggableList/DraggableList.jsx

View check run for this annotation

Codecov / codecov/patch

src/generic/DraggableList/DraggableList.jsx#L86

Added line #L86 was not covered by tests
};

DraggableList.propTypes = {
itemList: PropTypes.arrayOf(PropTypes.shape({
id: PropTypes.string.isRequired,
})).isRequired,
setState: PropTypes.func.isRequired,
updateOrder: PropTypes.func.isRequired,
children: PropTypes.node.isRequired,
renderOverlay: PropTypes.func,
activeId: PropTypes.string,
setActiveId: PropTypes.func,
};

export default DraggableList;
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const SortableItem = ({
children,
isClickable,
onClick,
disabled,
// injected
intl,
}) => {
Expand All @@ -31,6 +32,9 @@ const SortableItem = ({
} = useSortable({
id,
animateLayoutChanges: () => false,
disabled: {
draggable: disabled,
},
});

const style = {
Expand All @@ -52,6 +56,7 @@ const SortableItem = ({
>
<ActionRow style={actionStyle}>
{actions}
{!disabled && (
<IconButtonWithTooltip
key="drag-to-reorder-icon"
ref={setActivatorNodeRef}
Expand All @@ -64,6 +69,7 @@ const SortableItem = ({
{...attributes}
{...listeners}
/>
)}
</ActionRow>
{children}
</Card>
Expand All @@ -76,6 +82,7 @@ SortableItem.defaultProps = {
actionStyle: null,
isClickable: false,
onClick: null,
disabled: false,
};
SortableItem.propTypes = {
id: PropTypes.string.isRequired,
Expand All @@ -85,6 +92,7 @@ SortableItem.propTypes = {
componentStyle: PropTypes.shape({}),
isClickable: PropTypes.bool,
onClick: PropTypes.func,
disabled: PropTypes.bool,
// injected
intl: intlShape.isRequired,
};
Expand Down
1 change: 0 additions & 1 deletion src/generic/styles.scss
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,5 @@
@import "./tag-count/TagCount";
@import "./modal-dropzone/ModalDropzone";
@import "./configure-modal/ConfigureModal";
@import "./drag-helper/SortableItem";
@import "./block-type-utils";
@import "./modal-iframe"
11 changes: 11 additions & 0 deletions src/library-authoring/data/api.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -126,4 +126,15 @@ describe('library data API', () => {
await api.addComponentsToContainer(containerId, [componentId]);
expect(axiosMock.history.post[0].url).toEqual(url);
});

it('should update container children', async () => {
const { axiosMock } = initializeMocks();
const containerId = 'lct:org:lib1';
const url = api.getLibraryContainerChildrenApiUrl(containerId);

axiosMock.onPatch(url).reply(200);

await api.updateLibraryContainerChildren(containerId, ['test']);
expect(axiosMock.history.patch[0].url).toEqual(url);
});
});
14 changes: 14 additions & 0 deletions src/library-authoring/data/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -670,3 +670,17 @@ export async function updateContainerCollections(containerId: string, collection
collection_keys: collectionKeys,
});
}

/**
* Update library container's children.
*/
export async function updateLibraryContainerChildren(
containerId: string,
children: string[],
): Promise<LibraryBlockMetadata[]> {
const { data } = await getAuthenticatedHttpClient().patch(
getLibraryContainerChildrenApiUrl(containerId),
{ usage_keys: children },
);
return camelCaseObject(data);
}
21 changes: 21 additions & 0 deletions src/library-authoring/data/apiHooks.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ import {
useRestoreContainer,
useContainerChildren,
useAddComponentsToContainer,
useUpdateContainerChildren,
} from './apiHooks';

let axiosMock;
Expand Down Expand Up @@ -266,4 +267,24 @@ describe('library api hooks', () => {

expect(axiosMock.history.post[0].url).toEqual(url);
});

it('should update container children', async () => {
const containerId = 'lct:org:lib1';
const url = getLibraryContainerChildrenApiUrl(containerId);

axiosMock.onPatch(url).reply(200);
const { result } = renderHook(() => useUpdateContainerChildren(containerId), { wrapper });
await result.current.mutateAsync([]);
await waitFor(() => {
expect(axiosMock.history.patch[0].url).toEqual(url);
});
});

it('should not attempt request if containerId is not defined', async () => {
const { result } = renderHook(() => useUpdateContainerChildren(), { wrapper });
await result.current.mutateAsync([]);
await waitFor(() => {
expect(axiosMock.history.patch.length).toEqual(0);
});
});
});
26 changes: 26 additions & 0 deletions src/library-authoring/data/apiHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ import {
restoreContainer,
getLibraryContainerChildren,
updateContainerCollections,
updateLibraryContainerChildren,
} from './api';
import { VersionSpec } from '../LibraryBlock';

Expand Down Expand Up @@ -696,3 +697,28 @@ export const useUpdateContainerCollections = (containerId: string) => {
},
});
};

/**
* Update container children
*/
export const useUpdateContainerChildren = (containerId?: string) => {
const queryClient = useQueryClient();
return useMutation({
mutationFn: async (usageKeys: string[]) => {
if (!containerId) {
return undefined;
}
return updateLibraryContainerChildren(containerId, usageKeys);
},
onSettled: () => {
if (!containerId) {
return;
}
// NOTE: We invalidate the library query here because we need to update the library's
// container list.
const libraryId = getLibraryId(containerId);
queryClient.invalidateQueries({ predicate: (query) => libraryQueryPredicate(query, libraryId) });
queryClient.invalidateQueries({ queryKey: libraryAuthoringQueryKeys.container(containerId) });
},
});
};
Loading