diff --git a/src/search-modal/SearchResult.jsx b/src/search-modal/SearchResult.jsx index 7fb4cb2599..634c12d016 100644 --- a/src/search-modal/SearchResult.jsx +++ b/src/search-modal/SearchResult.jsx @@ -41,7 +41,7 @@ function getItemIcon(blockType) { */ function getLibraryHitUrl(hit, libraryAuthoringMfeUrl) { const { contextKey } = hit; - return `${libraryAuthoringMfeUrl}/library/${contextKey}`; + return `${libraryAuthoringMfeUrl}library/${contextKey}`; } /** @@ -62,10 +62,20 @@ function getUnitUrlSuffix(hit) { function getUnitComponentUrlSuffix(hit) { const { breadcrumbs, contextKey, usageKey } = hit; if (breadcrumbs.length > 1) { - const parent = breadcrumbs[breadcrumbs.length - 1]; + let parent = breadcrumbs[breadcrumbs.length - 1]; if ('usageKey' in parent) { - return `course/${contextKey}/container/${parent.usageKey}?show=${encodeURIComponent(usageKey)}`; + // Handle case for library component in unit + let libComponentUsageKey; + if (parent.usageKey.includes('type@library_content') && breadcrumbs.length > 2) { + libComponentUsageKey = parent.usageKey; + parent = breadcrumbs[breadcrumbs.length - 2]; + } + + if ('usageKey' in parent) { + const encodedUsageKey = encodeURIComponent(libComponentUsageKey || usageKey); + return `course/${contextKey}/container/${parent.usageKey}?show=${encodedUsageKey}`; + } } } @@ -96,11 +106,13 @@ function getUrlSuffix(hit) { return getUnitUrlSuffix(hit); } - // Check if the parent is a unit + // Check if the parent is a unit or a library component in a unit if (breadcrumbs.length > 1) { const parent = breadcrumbs[breadcrumbs.length - 1]; - if ('usageKey' in parent && parent.usageKey.includes('type@vertical')) { + if ('usageKey' in parent && ( + parent.usageKey.includes('type@vertical') || parent.usageKey.includes('type@library_content')) + ) { return getUnitComponentUrlSuffix(hit); } } diff --git a/src/search-modal/SearchUI.test.jsx b/src/search-modal/SearchUI.test.jsx index 0d5aeb697e..c653807dfb 100644 --- a/src/search-modal/SearchUI.test.jsx +++ b/src/search-modal/SearchUI.test.jsx @@ -290,6 +290,31 @@ describe('', () => { ); }); + test('click lib component in unit result navigates to the context of encompassing lib component', async () => { + const { findAllByRole } = rendered; + + const [resultItem] = await findAllByRole('button', { name: /Text block in Lib Component/ }); + + // Clicking the "Open in new window" button should open the result in a new window: + const { open } = window; + window.open = jest.fn(); + fireEvent.click(within(resultItem).getByRole('button', { name: 'Open in new window' })); + + expect(window.open).toHaveBeenCalledWith( + '/course/course-v1:SampleTaxonomyOrg1+STC1+2023_1/container/block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@aaf8b8eb86b54281aeeab12499d2cb0b' + + '?show=block-v1%3ASampleTaxonomyOrg1%2BSTC1%2B2023_1%2Btype%40library_content%2Bblock%40427e5cd03fbe431d9d551c67d4e280ae', + '_blank', + ); + window.open = open; + + // Clicking in the result should navigate to the result's URL: + fireEvent.click(resultItem); + expect(mockNavigate).toHaveBeenCalledWith( + '/course/course-v1:SampleTaxonomyOrg1+STC1+2023_1/container/block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@aaf8b8eb86b54281aeeab12499d2cb0b' + + '?show=block-v1%3ASampleTaxonomyOrg1%2BSTC1%2B2023_1%2Btype%40library_content%2Bblock%40427e5cd03fbe431d9d551c67d4e280ae', + ); + }); + test('click lib component result navigates to the context', async () => { const data = generateGetStudioHomeDataApiResponse(); data.redirectToLibraryAuthoringMfe = true; diff --git a/src/search-modal/__mocks__/search-result.json b/src/search-modal/__mocks__/search-result.json index 86a2eeeb15..9e60dfaa93 100644 --- a/src/search-modal/__mocks__/search-result.json +++ b/src/search-modal/__mocks__/search-result.json @@ -262,6 +262,76 @@ "org": "SampleTaxonomyOrg1", "access_id": "6" } + }, + { + "display_name": "Text block in Lib Component", + "block_id": "b654d61248bcc1f84c08", + "content": { + "html_content": " This is a text block lib component. " + }, + "id": "block-v1sampletaxonomyorg1stc12023_1typehtmlblockb654d61248bcc1f84c08-77f1f658", + "type": "course_block", + "breadcrumbs": [ + { + "display_name": "Sample Taxonomy Course" + }, + { + "display_name": "Section 1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@chapter+block@c7077c8cafcf420dbc0b440bf27bad04" + }, + { + "display_name": "Subsection 1.1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@sequential+block@92e3e9ca156c44fa8a735f0e9e7c854f" + }, + { + "display_name": "Unit 1.1.1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@aaf8b8eb86b54281aeeab12499d2cb0b" + }, + { + "display_name": "Randomized Content Block", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@library_content+block@427e5cd03fbe431d9d551c67d4e280ae" + } + ], + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@html+block@b654d61248bcc1f84c08", + "block_type": "html", + "context_key": "course-v1:SampleTaxonomyOrg1+STC1+2023_1", + "org": "SampleTaxonomyOrg1", + "access_id": 6, + "_formatted": { + "display_name": "Text block in Lib Component", + "block_id": "b654d61248bcc1f84c08", + "content": { + "html_content": " This is a text block lib component. " + }, + "id": "block-v1sampletaxonomyorg1stc12023_1typehtmlblockb654d61248bcc1f84c08-77f1f658", + "type": "course_block", + "breadcrumbs": [ + { + "display_name": "Sample Taxonomy Course" + }, + { + "display_name": "Section 1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@chapter+block@c7077c8cafcf420dbc0b440bf27bad04" + }, + { + "display_name": "Subsection 1.1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@sequential+block@92e3e9ca156c44fa8a735f0e9e7c854f" + }, + { + "display_name": "Unit 1.1.1", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@vertical+block@aaf8b8eb86b54281aeeab12499d2cb0b" + }, + { + "display_name": "Randomized Content Block", + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@library_content+block@427e5cd03fbe431d9d551c67d4e280ae" + } + ], + "usage_key": "block-v1:SampleTaxonomyOrg1+STC1+2023_1+type@html+block@b654d61248bcc1f84c08", + "block_type": "html", + "context_key": "course-v1:SampleTaxonomyOrg1+STC1+2023_1", + "org": "SampleTaxonomyOrg1", + "access_id": "6" + } } ], "query": "learn", diff --git a/src/studio-home/factories/mockApiResponses.jsx b/src/studio-home/factories/mockApiResponses.jsx index ae110e8f6f..30615ba8d5 100644 --- a/src/studio-home/factories/mockApiResponses.jsx +++ b/src/studio-home/factories/mockApiResponses.jsx @@ -32,7 +32,7 @@ export const generateGetStudioHomeDataApiResponse = () => ({ inProcessCourseActions: [], libraries: [], librariesEnabled: true, - libraryAuthoringMfeUrl: 'http://localhost:3001', + libraryAuthoringMfeUrl: 'http://localhost:3001/', optimizationEnabled: false, redirectToLibraryAuthoringMfe: false, requestCourseCreatorUrl: '/request_course_creator',