Skip to content
Merged
Show file tree
Hide file tree
Changes from 48 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
5cb979d
feat: library section page
navinkarkera May 23, 2025
6033db1
fixup! feat: library section page
navinkarkera May 24, 2025
b1f318e
fixup! feat: library section page
navinkarkera May 26, 2025
035c7fa
fixup! feat: library section page
navinkarkera May 26, 2025
0db3eb5
fix: update children on child name update
navinkarkera May 26, 2025
cea088c
fix: navigation to newly created container
navinkarkera May 27, 2025
c2114a9
fix: getBlockType for containers
navinkarkera May 27, 2025
1a17ad1
style: section page
navinkarkera May 27, 2025
871eff4
fix: remove unused variable
navinkarkera May 27, 2025
14c8657
chore: fix message
navinkarkera May 27, 2025
67d2c2d
refactor: extract header action component
navinkarkera May 27, 2025
5bebab4
refactor: extract footer actions and simplify content picker
navinkarkera May 27, 2025
27dba10
refactor: imports
navinkarkera May 27, 2025
b96bca3
feat: add subsection page and refactor id handling
navinkarkera May 28, 2025
dc101ba
fix: variable names
navinkarkera May 28, 2025
e3fad17
fix: collection page loading and remove collection option in menu
navinkarkera May 29, 2025
2ee04df
feat: subsection page breadcrumbs
navinkarkera May 29, 2025
563ae45
refactor: component selection in container pages and add draft tag
navinkarkera May 29, 2025
5cc77a6
style: subsection breadcrumbs
navinkarkera May 29, 2025
22db945
fix: lint issues
navinkarkera May 29, 2025
198381b
fix: context state
navinkarkera May 29, 2025
3cd2a42
fix: lint issues
navinkarkera May 29, 2025
a5e576a
fix: sidebar opening from new pages
navinkarkera May 30, 2025
e520b21
fix: lint issues
navinkarkera May 30, 2025
cfea873
refactor: convert SortableItem to typescript and fix types
navinkarkera May 30, 2025
629e269
fix: children wiggle in section and subection page
navinkarkera May 30, 2025
d36b7d7
fix: lint issues
navinkarkera May 30, 2025
e4357f3
refactor: context handling
navinkarkera May 30, 2025
d8ef2ca
test: fix failing tests
navinkarkera May 30, 2025
c05f95f
test: PickLibraryContentModal
navinkarkera May 30, 2025
f7925a7
test: ContainerCard
navinkarkera May 30, 2025
d071771
chore: add ignore statement
navinkarkera May 31, 2025
9fa088f
Merge branch 'master' into navin/fal-4164/section-subsection-page
navinkarkera May 31, 2025
d2e4f5c
refactor: remove injected intl code
navinkarkera May 31, 2025
134c4dc
refactor: check container type before navigation
navinkarkera May 31, 2025
b91abd6
fix: include navigateTo in dependency array
navinkarkera May 31, 2025
4c5f304
fix: component picker filter in course and container children editing…
navinkarkera May 31, 2025
a51dc22
fix: add missing key
navinkarkera May 31, 2025
50a73e4
refactor: context
navinkarkera May 31, 2025
1d18983
fix: pick lib content component id check
navinkarkera Jun 1, 2025
81cfb18
fix: case statement in PickLibraryContentModal test case
navinkarkera Jun 1, 2025
fdee2fb
test: library section page
navinkarkera Jun 1, 2025
eb6a49d
test: subsection page
navinkarkera Jun 2, 2025
3a05e2d
fix: lint issues
navinkarkera Jun 2, 2025
976006f
test: fix failing tests
navinkarkera Jun 2, 2025
fb8ab56
Merge branch 'master' into navin/fal-4164/section-subsection-page
navinkarkera Jun 3, 2025
1bcce12
fix: lint issues
navinkarkera Jun 3, 2025
e5a508e
fix: show subsections tab only in add modal in section page
navinkarkera Jun 3, 2025
aea42e8
refactor: replace getContainerTypeFromId with getBlockType
navinkarkera Jun 4, 2025
4e8bc27
fix: lint issues
navinkarkera Jun 4, 2025
e36b5ae
Merge branch 'master' into navin/fal-4164/section-subsection-page
navinkarkera Jun 4, 2025
5205375
refactor: rename fn
navinkarkera Jun 4, 2025
041db18
test: empty section and subsection page
navinkarkera Jun 4, 2025
dc5f4f4
feat: invalidate all parent containers on name update
navinkarkera Jun 4, 2025
a905019
refactor: invalidate all container data on name update
navinkarkera Jun 4, 2025
6498ff3
fix: lint issues
navinkarkera Jun 4, 2025
0658029
refactor: Delete catch on handleOnChangeText in InplaceTextEditor
ChrisChV Jun 4, 2025
1c8518e
fix: Broken tests
ChrisChV Jun 4, 2025
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
Original file line number Diff line number Diff line change
@@ -1,14 +1,25 @@
import React from 'react';
import PropTypes from 'prop-types';
import { intlShape, injectIntl } from '@edx/frontend-platform/i18n';
import React, { MouseEventHandler } from 'react';
import { useSortable } from '@dnd-kit/sortable';
import { CSS } from '@dnd-kit/utilities';
import {
ActionRow, Card, Icon, IconButtonWithTooltip,
} from '@openedx/paragon';
import { DragIndicator } from '@openedx/paragon/icons';
import { useIntl } from '@edx/frontend-platform/i18n';
import messages from './messages';

interface SortableItemProps {
id: string,
children?: React.ReactNode | null,
actions: React.ReactNode | null,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: ReactNode typing already includes null

Suggested change
children?: React.ReactNode | null,
actions: React.ReactNode | null,
children?: React.ReactNode,
actions: React.ReactNode,

actionStyle?: {},
componentStyle?: {},
isClickable?: boolean,
onClick?: MouseEventHandler,
disabled?: boolean,
cardClassName?: string,
}

const SortableItem = ({
id,
componentStyle,
Expand All @@ -19,9 +30,8 @@ const SortableItem = ({
onClick,
disabled,
cardClassName = '',
// injected
intl,
}) => {
}: SortableItemProps) => {
const intl = useIntl();
const {
attributes,
listeners,
Expand Down Expand Up @@ -78,26 +88,5 @@ const SortableItem = ({
</div>
);
};
SortableItem.defaultProps = {
componentStyle: null,
actions: null,
actionStyle: null,
isClickable: false,
onClick: null,
disabled: false,
};
SortableItem.propTypes = {
id: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
actions: PropTypes.node,
actionStyle: PropTypes.shape({}),
componentStyle: PropTypes.shape({}),
isClickable: PropTypes.bool,
onClick: PropTypes.func,
disabled: PropTypes.bool,
cardClassName: PropTypes.string,
// injected
intl: intlShape.isRequired,
};

export default injectIntl(SortableItem);
export default SortableItem;
2 changes: 1 addition & 1 deletion src/generic/key-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
* @returns The block type as a string
*/
export function getBlockType(usageKey: string): string {
if (usageKey && usageKey.startsWith('lb:')) {
if (usageKey && (usageKey.startsWith('lb:') || usageKey.startsWith('lct:'))) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This change means we don't really need getContainerTypeFromId -- since it's only really used in one place, could we move its tests over to this method and remove it entirely?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. aea42e8

const blockType = usageKey.split(':')[3];
if (blockType) {
return blockType;
Expand Down
15 changes: 13 additions & 2 deletions src/library-authoring/LibraryLayout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,12 @@ import LibraryCollectionPage from './collections/LibraryCollectionPage';
import { ComponentPicker } from './component-picker';
import { ComponentEditorModal } from './components/ComponentEditorModal';
import { LibraryUnitPage } from './units';
import { LibrarySectionPage, LibrarySubsectionPage } from './section-subsections';

const LibraryLayoutWrapper: React.FC<React.PropsWithChildren> = ({ children }) => {
const { libraryId, collectionId, unitId } = useParams();
const {
libraryId, collectionId, unitId, sectionId, subsectionId,
} = useParams();

if (libraryId === undefined) {
// istanbul ignore next - This shouldn't be possible; it's just here to satisfy the type checker.
Expand All @@ -31,7 +34,7 @@ const LibraryLayoutWrapper: React.FC<React.PropsWithChildren> = ({ children }) =
* when we navigate to a collection or unit page. This is necessary to make the back/forward navigation
* work correctly, as the LibraryProvider needs to rebuild the state from the URL.
* */
key={collectionId || unitId}
key={collectionId || sectionId || subsectionId || unitId}
libraryId={libraryId}
/** NOTE: The component picker modal to use. We need to pass it as a reference instead of
* directly importing it to avoid the import cycle:
Expand Down Expand Up @@ -70,6 +73,14 @@ const LibraryLayout = () => (
path={ROUTES.COLLECTION}
Component={LibraryCollectionPage}
/>
<Route
path={ROUTES.SECTION}
Component={LibrarySectionPage}
/>
<Route
path={ROUTES.SUBSECTION}
Component={LibrarySubsectionPage}
/>
<Route
path={ROUTES.UNIT}
Component={LibraryUnitPage}
Expand Down
148 changes: 148 additions & 0 deletions src/library-authoring/__mocks__/subsection-single.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
{
"comment": "This mock is captured from a real search result and roughly edited to match the mocks in src/library-authoring/data/api.mocks.ts",
"note": "The _formatted fields have been removed from this result and should be re-added programatically when mocking.",
"results": [
{
"indexUid": "studio_content",
"hits": [
{
"display_name": "Test Subsection",
"block_id": "subsection-1",
"content": {
"child_usage_keys": [
"lb:org1:Demo_course:unit:unit-0",
"lb:org1:Demo_course:unit:unit-1",
"lb:org1:Demo_course:unit:unit-2"
],
"child_display_names": [
"unit block 0",
"unit block 1",
"unit block 2"
]
},
"tags": {},
"collections": {
"display_name": [
"Collection 1"
],
"key": [
"collection-1"
]
},
"id": "lctunixcs1subsectiontest-subsection-4-861b09-bc0507a2",
"type": "library_container",
"breadcrumbs": [
{
"display_name": "CS 1"
}
],
"created": 1748341802.87277,
"modified": 1748790449.393821,
"last_published": 1748536425.317183,
"publish_status": "modified",
"usage_key": "lct:UNIX:CS1:subsection:test-subsection-4-861b09",
"block_type": "subsection",
"context_key": "lib:UNIX:CS1",
"org": "UNIX",
"access_id": 1,
"published": {
"display_name": "Test subsection 42",
"num_children": 2,
"content": {
"child_usage_keys": [
"lb:org1:Demo_course:unit:unit-0",
"lb:org1:Demo_course:unit:unit-1"
],
"child_display_names": [
"unit block 0",
"unit block 1"
]
}
},
"num_children": 4,
"sections": {
"display_name": [
"Test section",
"Test section 51"
],
"key": [
"lct:org:lib:section:test-section-1",
"lct:org:lib:section:test-section-2"
]
},
"_formatted": {
"display_name": "Test Subsection",
"block_id": "subsection-1",
"content": {
"child_usage_keys": [
"lb:org1:Demo_course:unit:unit-0",
"lb:org1:Demo_course:unit:unit-1",
"lb:org1:Demo_course:unit:unit-2"
],
"child_display_names": [
"unit block 0",
"unit block 1",
"unit block 2"
]
},
"tags": {},
"collections": {
"display_name": [
"Collection 1"
],
"key": [
"collection-1"
]
},
"id": "lctunixcs1subsectiontest-subsection-4-861b09-bc0507a2",
"type": "library_container",
"breadcrumbs": [
{
"display_name": "CS 1"
}
],
"created": "1748341802.87277",
"modified": "1748790449.393821",
"last_published": "1748536425.317183",
"publish_status": "modified",
"usage_key": "lct:UNIX:CS1:subsection:test-subsection-4-861b09",
"block_type": "subsection",
"context_key": "lib:UNIX:CS1",
"org": "UNIX",
"access_id": "1",
"published": {
"display_name": "Test subsection 42",
"num_children": "2",
"content": {
"child_usage_keys": [
"lb:org1:Demo_course:unit:unit-0",
"lb:org1:Demo_course:unit:unit-1"
],
"child_display_names": [
"unit block 0",
"unit block 1"
]
}
},
"num_children": "4",
"sections": {
"display_name": [
"Test section 11",
"Test section 51"
],
"key": [
"lct:UNIX:CS1:section:test-section-1-415565",
"lct:UNIX:CS1:section:test-section-5-0c65f3"
]
}
}
}
],
"query": "",
"processingTimeMs": 1,
"limit": 20,
"offset": 0,
"estimatedTotalHits": 10
}
]
}
16 changes: 4 additions & 12 deletions src/library-authoring/add-content/AddContent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,13 @@ import {
useLibraryPasteClipboard,
useBlockTypesMetadata,
useAddItemsToCollection,
useAddComponentsToContainer,
useAddChildrenToContainer,
} from '../data/apiHooks';
import { useLibraryContext } from '../common/context/LibraryContext';
import { PickLibraryContentModal } from './PickLibraryContentModal';
import { blockTypes } from '../../editors/data/constants/app';

import { ContentType as LibraryContentTypes, useLibraryRoutes } from '../routes';
import { useLibraryRoutes } from '../routes';
import genericMessages from '../generic/messages';
import messages from './messages';
import type { BlockTypeMetadata } from '../data/api';
Expand Down Expand Up @@ -88,10 +88,7 @@ const AddContentView = ({
closeAddLibraryContentModal,
}: AddContentViewProps) => {
const intl = useIntl();
const {
componentPicker,
unitId,
} = useLibraryContext();
const { componentPicker } = useLibraryContext();
const {
insideCollection,
insideUnit,
Expand Down Expand Up @@ -129,9 +126,6 @@ const AddContentView = ({
blockType: 'libraryContent',
};

const extraFilter = unitId ? ['NOT block_type = "unit"', 'NOT type = "collections"'] : undefined;
const visibleTabs = unitId ? [LibraryContentTypes.components] : undefined;

/** List container content types that should be displayed based on current path */
const visibleContentTypes = useMemo(() => {
if (insideCollection) {
Expand Down Expand Up @@ -182,8 +176,6 @@ const AddContentView = ({
<PickLibraryContentModal
isOpen={isAddLibraryContentModalOpen}
onClose={closeAddLibraryContentModal}
extraFilter={extraFilter}
visibleTabs={visibleTabs}
/>
)}
<hr className="w-100 bg-gray-500" />
Expand Down Expand Up @@ -276,7 +268,7 @@ const AddContent = () => {
insideUnit,
} = useLibraryRoutes();
const addComponentsToCollectionMutation = useAddItemsToCollection(libraryId, collectionId);
const addComponentsToContainerMutation = useAddComponentsToContainer(unitId);
const addComponentsToContainerMutation = useAddChildrenToContainer(unitId);
const createBlockMutation = useCreateLibraryBlock();
const pasteClipboardMutation = useLibraryPasteClipboard();
const { showToast } = useContext(ToastContext);
Expand Down
Loading