From 7394deab2c98de978e18f00f0db13c49d8699bb4 Mon Sep 17 00:00:00 2001 From: Navin Karkera Date: Thu, 17 Oct 2024 12:01:07 +0530 Subject: [PATCH] feat: direct link to single block in library Adds support for displaying single xblock in a library when passed a query param: usageKey. This is required for directing users to a specific block from course. --- .../components/LibraryComponents.tsx | 7 ++++++- src/search-manager/SearchKeywordsField.tsx | 9 +++++---- src/search-manager/SearchManager.ts | 14 ++++++++++++++ src/search-manager/messages.ts | 5 +++++ 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/src/library-authoring/components/LibraryComponents.tsx b/src/library-authoring/components/LibraryComponents.tsx index c260897b64..c3a7758ec0 100644 --- a/src/library-authoring/components/LibraryComponents.tsx +++ b/src/library-authoring/components/LibraryComponents.tsx @@ -26,8 +26,13 @@ const LibraryComponents = ({ variant }: LibraryComponentsProps) => { fetchNextPage, isLoading, isFiltered, + usageKey, } = useSearchContext(); - const { openAddContentSidebar } = useLibraryContext(); + const { openAddContentSidebar, openComponentInfoSidebar } = useLibraryContext(); + + if (usageKey) { + openComponentInfoSidebar(usageKey); + } const componentList = variant === 'preview' ? hits.slice(0, LIBRARY_SECTION_PREVIEW_LIMIT) : hits; diff --git a/src/search-manager/SearchKeywordsField.tsx b/src/search-manager/SearchKeywordsField.tsx index a60a54cd02..14a6a06dc9 100644 --- a/src/search-manager/SearchKeywordsField.tsx +++ b/src/search-manager/SearchKeywordsField.tsx @@ -9,7 +9,9 @@ import { useSearchContext } from './SearchManager'; */ const SearchKeywordsField: React.FC<{ className?: string, placeholder?: string }> = (props) => { const intl = useIntl(); - const { searchKeywords, setSearchKeywords } = useSearchContext(); + const { searchKeywords, setSearchKeywords, usageKey } = useSearchContext(); + const defaultPlaceholder = usageKey ? messages.clearUsageKeyToSearch : messages.inputPlaceholder; + const { placeholder = intl.formatMessage(defaultPlaceholder) } = props; return ( setSearchKeywords('')} value={searchKeywords} className={props.className} + disabled={!!usageKey} > diff --git a/src/search-manager/SearchManager.ts b/src/search-manager/SearchManager.ts index 413e4ff760..8712376558 100644 --- a/src/search-manager/SearchManager.ts +++ b/src/search-manager/SearchManager.ts @@ -44,6 +44,7 @@ export interface SearchContextData { hasError: boolean; collectionHits: CollectionHit[]; totalCollectionHits: number; + usageKey: string; } const SearchContext = React.createContext(undefined); @@ -101,7 +102,17 @@ export const SearchContextProvider: React.FC<{ const [blockTypesFilter, setBlockTypesFilter] = React.useState([]); const [problemTypesFilter, setProblemTypesFilter] = React.useState([]); const [tagsFilter, setTagsFilter] = React.useState([]); + const [usageKey, setUsageKey] = useStateWithUrlSearchParam( + '', + 'usageKey', + (value: string) => value, + (value: string) => value, + ); + let extraFilter: string[] = forceArray(props.extraFilter); + if (usageKey) { + extraFilter.push(`usage_key = "${usageKey}"`); + } // The search sort order can be set via the query string // E.g. ?sort=display_name:desc maps to SearchSortOption.TITLE_ZA. @@ -131,12 +142,14 @@ export const SearchContextProvider: React.FC<{ blockTypesFilter.length > 0 || problemTypesFilter.length > 0 || tagsFilter.length > 0 + || !!usageKey ); const isFiltered = canClearFilters || (searchKeywords !== ''); const clearFilters = React.useCallback(() => { setBlockTypesFilter([]); setTagsFilter([]); setProblemTypesFilter([]); + setUsageKey(''); }, []); // Initialize a connection to Meilisearch: @@ -176,6 +189,7 @@ export const SearchContextProvider: React.FC<{ defaultSearchSortOrder, closeSearchModal: props.closeSearchModal ?? (() => { }), hasError: hasConnectionError || result.isError, + usageKey, ...result, }, }, props.children); diff --git a/src/search-manager/messages.ts b/src/search-manager/messages.ts index 218b452e1e..aca799f93c 100644 --- a/src/search-manager/messages.ts +++ b/src/search-manager/messages.ts @@ -11,6 +11,11 @@ const messages = defineMessages({ defaultMessage: 'Search', description: 'Placeholder text shown in the keyword input field when the user has not yet entered a keyword', }, + clearUsageKeyToSearch: { + id: 'course-authoring.search-manager.clearUsageKeyToSearch', + defaultMessage: 'Displaying single block, clear filters to search', + description: 'Placeholder text shown in the keyword input field when a single block filtered by usage key is shown', + }, blockTypeFilter: { id: 'course-authoring.search-manager.blockTypeFilter', defaultMessage: 'Type',