From 1ae553cce7b89804fd562234183654d249c76d97 Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Wed, 16 Apr 2025 18:55:02 +0930 Subject: [PATCH 1/3] fix: use Library search results to populate container card preview --- .../components/ContainerCard.test.tsx | 21 +++++++++------- .../components/ContainerCard.tsx | 25 +++++++++---------- src/search-manager/data/api.ts | 4 +++ 3 files changed, 28 insertions(+), 22 deletions(-) diff --git a/src/library-authoring/components/ContainerCard.test.tsx b/src/library-authoring/components/ContainerCard.test.tsx index a76601e1d0..9b70191245 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,33 @@ 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(); }); }); diff --git a/src/library-authoring/components/ContainerCard.tsx b/src/library-authoring/components/ContainerCard.tsx index 45268aa150..6b5cda807a 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,19 @@ const ContainerMenu = ({ hit } : ContainerMenuProps) => { }; type ContainerCardPreviewProps = { - containerId: string; + hit: ContainerHit, 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 = ({ hit, showMaxChildren = 5 }: ContainerCardPreviewProps) => { + const { content } = hit; + const { childUsageKeys } = content ?? { childUsageKeys: [] }; + 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 +132,7 @@ const ContainerCardPreview = ({ containerId, showMaxChildren = 5 }: ContainerCar ); } else { @@ -147,7 +146,7 @@ const ContainerCardPreview = ({ containerId, showMaxChildren = 5 }: ContainerCar } return (
{blockPreview} @@ -200,7 +199,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..36da3a805d 100644 --- a/src/search-manager/data/api.ts +++ b/src/search-manager/data/api.ts @@ -171,6 +171,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 +181,7 @@ export interface ContainerHit extends BaseContentHit { published?: ContentPublishedData; publishStatus: PublishStatus; formatted: BaseContentHit['formatted'] & { published?: ContentPublishedData, }; + content?: ContainerHitContent; } export type HitType = ContentHit | CollectionHit | ContainerHit; From abc3b5dd22c8564f82892ff9af5e9d3e8f80c91c Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Tue, 29 Apr 2025 16:35:15 +0930 Subject: [PATCH 2/3] feat: show published children when showing only published Unit content --- .../components/ContainerCard.test.tsx | 21 +++++++++++++++++++ .../components/ContainerCard.tsx | 16 ++++++++------ src/search-manager/data/api.ts | 10 +++++---- 3 files changed, 37 insertions(+), 10 deletions(-) diff --git a/src/library-authoring/components/ContainerCard.test.tsx b/src/library-authoring/components/ContainerCard.test.tsx index 9b70191245..a8716d7ad1 100644 --- a/src/library-authoring/components/ContainerCard.test.tsx +++ b/src/library-authoring/components/ContainerCard.test.tsx @@ -183,4 +183,25 @@ describe('', () => { 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 6b5cda807a..2f4b0daf88 100644 --- a/src/library-authoring/components/ContainerCard.tsx +++ b/src/library-authoring/components/ContainerCard.tsx @@ -108,13 +108,11 @@ const ContainerMenu = ({ hit } : ContainerMenuProps) => { }; type ContainerCardPreviewProps = { - hit: ContainerHit, + childUsageKeys: Array; showMaxChildren?: number; }; -const ContainerCardPreview = ({ hit, showMaxChildren = 5 }: ContainerCardPreviewProps) => { - const { content } = hit; - const { childUsageKeys } = content ?? { childUsageKeys: [] }; +const ContainerCardPreview = ({ childUsageKeys, showMaxChildren = 5 }: ContainerCardPreviewProps) => { const hiddenChildren = childUsageKeys.length - showMaxChildren; return ( @@ -172,9 +170,10 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { formatted, tags, numChildren, - published, + published = {}, publishStatus, usageKey: unitId, + content = {}, } = hit; const numChildrenCount = showOnlyPublished ? ( @@ -185,6 +184,11 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { showOnlyPublished ? formatted.published?.displayName : formatted.displayName ) ?? ''; + published.content = published?.content ?? {}; + const childUsageKeys: Array = ( + showOnlyPublished ? published.content?.childUsageKeys : content?.childUsageKeys + ) ?? []; + const { navigateTo } = useLibraryRoutes(); const openContainer = useCallback(() => { @@ -199,7 +203,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 36da3a805d..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; } /** @@ -172,7 +174,7 @@ export interface CollectionHit extends BaseContentHit { * Defined in edx-platform/openedx/core/djangoapps/content/search/documents.py */ interface ContainerHitContent { - childUsageKeys: string[], + childUsageKeys?: string[], } export interface ContainerHit extends BaseContentHit { type: 'library_container'; From d53629c896d8cfc6b576841ed01ebd5625afac8d Mon Sep 17 00:00:00 2001 From: Jillian Vogel Date: Thu, 1 May 2025 16:13:58 +0930 Subject: [PATCH 3/3] fix: nits --- src/library-authoring/components/ContainerCard.tsx | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/library-authoring/components/ContainerCard.tsx b/src/library-authoring/components/ContainerCard.tsx index 2f4b0daf88..a1d3115a61 100644 --- a/src/library-authoring/components/ContainerCard.tsx +++ b/src/library-authoring/components/ContainerCard.tsx @@ -144,7 +144,9 @@ const ContainerCardPreview = ({ childUsageKeys, showMaxChildren = 5 }: Container } return (
{blockPreview} @@ -170,10 +172,10 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { formatted, tags, numChildren, - published = {}, + published, publishStatus, usageKey: unitId, - content = {}, + content, } = hit; const numChildrenCount = showOnlyPublished ? ( @@ -184,9 +186,8 @@ const ContainerCard = ({ hit } : ContainerCardProps) => { showOnlyPublished ? formatted.published?.displayName : formatted.displayName ) ?? ''; - published.content = published?.content ?? {}; const childUsageKeys: Array = ( - showOnlyPublished ? published.content?.childUsageKeys : content?.childUsageKeys + showOnlyPublished ? published?.content?.childUsageKeys : content?.childUsageKeys ) ?? []; const { navigateTo } = useLibraryRoutes();