diff --git a/src/library-authoring/components/ContainerCard.test.tsx b/src/library-authoring/components/ContainerCard.test.tsx index a76601e1d0..a8716d7ad1 100644 --- a/src/library-authoring/components/ContainerCard.test.tsx +++ b/src/library-authoring/components/ContainerCard.test.tsx @@ -6,7 +6,7 @@ import { fireEvent, } from '../../testUtils'; import { LibraryProvider } from '../common/context/LibraryContext'; -import { mockContentLibrary, mockGetContainerChildren } from '../data/api.mocks'; +import { mockContentLibrary } from '../data/api.mocks'; import { type ContainerHit, PublishStatus } from '../../search-manager'; import ContainerCard from './ContainerCard'; import { getLibraryContainerApiUrl, getLibraryContainerRestoreApiUrl } from '../data/api'; @@ -40,7 +40,6 @@ let axiosMock: MockAdapter; let mockShowToast; mockContentLibrary.applyMock(); -mockGetContainerChildren.applyMock(); const render = (ui: React.ReactElement, showOnlyPublished: boolean = false) => baseRender(ui, { extraWrapper: ({ children }) => ( @@ -155,29 +154,54 @@ describe('', () => { it('should render no child blocks in card preview', async () => { render(); - expect(screen.queryByTitle('text block')).not.toBeInTheDocument(); + expect(screen.queryByTitle('lb:org1:Demo_course:html:text-0')).not.toBeInTheDocument(); expect(screen.queryByText('+0')).not.toBeInTheDocument(); }); it('should render <=5 child blocks in card preview', async () => { const containerWith5Children = { ...containerHitSample, - usageKey: mockGetContainerChildren.fiveChildren, - }; + content: { + childUsageKeys: Array(5).fill('').map((_child, idx) => `lb:org1:Demo_course:html:text-${idx}`), + }, + } satisfies ContainerHit; render(); - expect((await screen.findAllByTitle(/text block */)).length).toBe(5); + expect((await screen.findAllByTitle(/lb:org1:Demo_course:html:text-*/)).length).toBe(5); expect(screen.queryByText('+0')).not.toBeInTheDocument(); }); it('should render >5 child blocks with +N in card preview', async () => { const containerWith6Children = { ...containerHitSample, - usageKey: mockGetContainerChildren.sixChildren, - }; + content: { + childUsageKeys: Array(6).fill('').map((_child, idx) => `lb:org1:Demo_course:html:text-${idx}`), + }, + } satisfies ContainerHit; render(); - expect((await screen.findAllByTitle(/text block */)).length).toBe(4); + expect((await screen.findAllByTitle(/lb:org1:Demo_course:html:text-*/)).length).toBe(4); expect(screen.queryByText('+2')).toBeInTheDocument(); }); + + it('should render published child blocks when rendering a published card preview', async () => { + const containerWithPublishedChildren = { + ...containerHitSample, + content: { + childUsageKeys: Array(6).fill('').map((_child, idx) => `lb:org1:Demo_course:html:text-${idx}`), + }, + published: { + content: { + childUsageKeys: Array(2).fill('').map((_child, idx) => `lb:org1:Demo_course:html:text-${idx}`), + }, + }, + } satisfies ContainerHit; + render( + , + true, + ); + + expect((await screen.findAllByTitle(/lb:org1:Demo_course:html:text-*/)).length).toBe(2); + expect(screen.queryByText('+2')).not.toBeInTheDocument(); + }); }); diff --git a/src/library-authoring/components/ContainerCard.tsx b/src/library-authoring/components/ContainerCard.tsx index b2f66e963f..a1d3115a61 100644 --- a/src/library-authoring/components/ContainerCard.tsx +++ b/src/library-authoring/components/ContainerCard.tsx @@ -12,12 +12,13 @@ import { MoreVert } from '@openedx/paragon/icons'; import { Link } from 'react-router-dom'; import { getItemIcon, getComponentStyleColor } from '../../generic/block-type-utils'; +import { getBlockType } from '../../generic/key-utils'; import { ToastContext } from '../../generic/toast-context'; import { type ContainerHit, PublishStatus } from '../../search-manager'; import { useComponentPickerContext } from '../common/context/ComponentPickerContext'; import { useLibraryContext } from '../common/context/LibraryContext'; import { SidebarActions, useSidebarContext } from '../common/context/SidebarContext'; -import { useContainerChildren, useRemoveItemsFromCollection } from '../data/apiHooks'; +import { useRemoveItemsFromCollection } from '../data/apiHooks'; import { useLibraryRoutes } from '../routes'; import AddComponentWidget from './AddComponentWidget'; import BaseCard from './BaseCard'; @@ -107,21 +108,17 @@ const ContainerMenu = ({ hit } : ContainerMenuProps) => { }; type ContainerCardPreviewProps = { - containerId: string; + childUsageKeys: Array; showMaxChildren?: number; }; -const ContainerCardPreview = ({ containerId, showMaxChildren = 5 }: ContainerCardPreviewProps) => { - const { data, isLoading, isError } = useContainerChildren(containerId); - if (isLoading || isError) { - return null; - } - - const hiddenChildren = data.length - showMaxChildren; +const ContainerCardPreview = ({ childUsageKeys, showMaxChildren = 5 }: ContainerCardPreviewProps) => { + const hiddenChildren = childUsageKeys.length - showMaxChildren; return ( { - data.slice(0, showMaxChildren).map(({ id, blockType, displayName }, idx) => { + childUsageKeys.slice(0, showMaxChildren).map((usageKey, idx) => { + const blockType = getBlockType(usageKey); let blockPreview: ReactNode; let classNames; @@ -133,7 +130,7 @@ const ContainerCardPreview = ({ containerId, showMaxChildren = 5 }: ContainerCar ); } else { @@ -149,7 +146,7 @@ const ContainerCardPreview = ({ containerId, showMaxChildren = 5 }: ContainerCar
{blockPreview} @@ -178,6 +175,7 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { published, publishStatus, usageKey: unitId, + content, } = hit; const numChildrenCount = showOnlyPublished ? ( @@ -188,6 +186,10 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { showOnlyPublished ? formatted.published?.displayName : formatted.displayName ) ?? ''; + const childUsageKeys: Array = ( + showOnlyPublished ? published?.content?.childUsageKeys : content?.childUsageKeys + ) ?? []; + const { navigateTo } = useLibraryRoutes(); const openContainer = useCallback(() => { @@ -202,7 +204,7 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { } + preview={} tags={tags} numChildren={numChildrenCount} actions={( diff --git a/src/search-manager/data/api.ts b/src/search-manager/data/api.ts index 549054b3fe..e1a6aeaa33 100644 --- a/src/search-manager/data/api.ts +++ b/src/search-manager/data/api.ts @@ -50,6 +50,7 @@ export const getContentSearchConfig = async (): Promise<{ url: string, indexName export interface ContentDetails { htmlContent?: string; capaContent?: string; + childUsageKeys?: Array; [k: string]: any; } @@ -151,9 +152,10 @@ export interface ContentHit extends BaseContentHit { * Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py */ export interface ContentPublishedData { - description?: string, - displayName?: string, - numChildren?: number, + description?: string; + displayName?: string; + numChildren?: number; + content?: ContentDetails; } /** @@ -171,6 +173,9 @@ export interface CollectionHit extends BaseContentHit { * Information about a single container returned in the search results * Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py */ +interface ContainerHitContent { + childUsageKeys?: string[], +} export interface ContainerHit extends BaseContentHit { type: 'library_container'; blockType: 'unit'; // This should be expanded to include other container types @@ -178,6 +183,7 @@ export interface ContainerHit extends BaseContentHit { published?: ContentPublishedData; publishStatus: PublishStatus; formatted: BaseContentHit['formatted'] & { published?: ContentPublishedData, }; + content?: ContainerHitContent; } export type HitType = ContentHit | CollectionHit | ContainerHit;