diff --git a/src/library-authoring/collections/CollectionDetails.tsx b/src/library-authoring/collections/CollectionDetails.tsx index 07076c334d..650fcd4af9 100644 --- a/src/library-authoring/collections/CollectionDetails.tsx +++ b/src/library-authoring/collections/CollectionDetails.tsx @@ -5,7 +5,7 @@ import classNames from 'classnames'; import { getItemIcon } from '../../generic/block-type-utils'; import { ToastContext } from '../../generic/toast-context'; -import { BlockTypeLabel, type CollectionHit, useSearchContext } from '../../search-manager'; +import { BlockTypeLabel, type CollectionHit, useGetBlockTypes } from '../../search-manager'; import type { ContentLibrary } from '../data/api'; import { useUpdateCollection } from '../data/apiHooks'; import HistoryWidget from '../generic/history-widget'; @@ -36,10 +36,19 @@ const BlockCount = ({ ); }; -const CollectionStatsWidget = () => { - const { - blockTypes, - } = useSearchContext(); +interface CollectionStatsWidgetProps { + collection: CollectionHit, +} + +const CollectionStatsWidget = ({ collection }: CollectionStatsWidgetProps) => { + const { data: blockTypes } = useGetBlockTypes([ + `context_key = "${collection.contextKey}"`, + `collections.key = "${collection.blockId}"`, + ]); + + if (!blockTypes) { + return null; + } const blockTypesArray = Object.entries(blockTypes) .map(([blockType, count]) => ({ blockType, count })) @@ -51,7 +60,12 @@ const CollectionStatsWidget = () => { if (totalBlocksCount === 0) { return ( -
+
); @@ -135,7 +149,7 @@ const CollectionDetails = ({ library, collection }: CollectionDetailsProps) => {

{intl.formatMessage(messages.detailsTabStatsTitle)}

- +

diff --git a/src/library-authoring/library-sidebar/LibrarySidebar.tsx b/src/library-authoring/library-sidebar/LibrarySidebar.tsx index 0d521e6b6f..d4466ef408 100644 --- a/src/library-authoring/library-sidebar/LibrarySidebar.tsx +++ b/src/library-authoring/library-sidebar/LibrarySidebar.tsx @@ -6,11 +6,7 @@ import { } from '@openedx/paragon'; import { Close } from '@openedx/paragon/icons'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { SearchParams } from 'meilisearch'; -import { - SearchContextProvider, -} from '../../search-manager'; import { AddContentContainer, AddContentHeader } from '../add-content'; import { CollectionInfo, CollectionInfoHeader } from '../collections'; import { ContentLibrary } from '../data/api'; @@ -68,36 +64,23 @@ const LibrarySidebar = ({ library }: LibrarySidebarProps) => { const buildBody = () : React.ReactNode => bodyComponentMap[sidebarBodyComponent || 'unknown']; const buildHeader = (): React.ReactNode => headerComponentMap[sidebarBodyComponent || 'unknown']; - const collectionQuery: SearchParams | undefined = currentCollectionHit ? { - filter: ['type = "collection"', `context_key = "${library.id}"`, `block_id = "${currentCollectionHit.blockId}"`], - limit: 1, - } : undefined; - return ( - - - - {buildHeader()} - - -
- {buildBody()} -
+ + + {buildHeader()} + -
+
+ {buildBody()} +
+ ); }; diff --git a/src/search-manager/SearchManager.ts b/src/search-manager/SearchManager.ts index bcce0779e7..cb1314b6b3 100644 --- a/src/search-manager/SearchManager.ts +++ b/src/search-manager/SearchManager.ts @@ -166,7 +166,7 @@ export const SearchContextProvider: React.FC<{ searchSortOrder, setSearchSortOrder, defaultSearchSortOrder, - closeSearchModal: props.closeSearchModal ?? (() => {}), + closeSearchModal: props.closeSearchModal ?? (() => { }), hasError: hasConnectionError || result.isError, ...result, }, diff --git a/src/search-manager/data/api.ts b/src/search-manager/data/api.ts index d343a7cdaa..5ae417a233 100644 --- a/src/search-manager/data/api.ts +++ b/src/search-manager/data/api.ts @@ -303,6 +303,29 @@ export async function fetchSearchResults({ }; } +/** + * Fetch the block types facet distribution for the search results. + */ +export const fetchBlockTypes = async ( + client: MeiliSearch, + indexName: string, + extraFilter?: Filter, +): Promise> => { + // Convert 'extraFilter' into an array + const extraFilterFormatted = forceArray(extraFilter); + + const { results } = await client.multiSearch({ + queries: [{ + indexUid: indexName, + facets: ['block_type', 'content.problem_types'], + filter: extraFilterFormatted, + limit: 0, // We don't need any "hits" for this - just the facetDistribution + }], + }); + + return results[0].facetDistribution?.block_type ?? {}; +}; + /** Information about a single tag in the tag tree, as returned by fetchAvailableTagOptions() */ export interface TagEntry { tagName: string; diff --git a/src/search-manager/data/apiHooks.ts b/src/search-manager/data/apiHooks.ts index c2a330c1e0..c22a004269 100644 --- a/src/search-manager/data/apiHooks.ts +++ b/src/search-manager/data/apiHooks.ts @@ -10,6 +10,7 @@ import { fetchTagsThatMatchKeyword, getContentSearchConfig, fetchDocumentById, + fetchBlockTypes, OverrideQueries, } from './api'; @@ -243,6 +244,22 @@ export const useTagFilterOptions = (args: { return { ...mainQuery, data }; }; +export const useGetBlockTypes = (extraFilters: Filter) => { + const { client, indexName } = useContentSearchConnection(); + return useQuery({ + enabled: client !== undefined && indexName !== undefined, + queryKey: [ + 'content_search', + client?.config.apiKey, + client?.config.host, + indexName, + extraFilters, + 'block_types', + ], + queryFn: () => fetchBlockTypes(client!, indexName!, extraFilters), + }); +}; + /* istanbul ignore next */ export const useGetSingleDocument = ({ client, indexName, id }: { client?: MeiliSearch; diff --git a/src/search-manager/index.ts b/src/search-manager/index.ts index 00117f6dcd..e2d4188be1 100644 --- a/src/search-manager/index.ts +++ b/src/search-manager/index.ts @@ -8,5 +8,6 @@ export { default as SearchKeywordsField } from './SearchKeywordsField'; export { default as SearchSortWidget } from './SearchSortWidget'; export { default as Stats } from './Stats'; export { HIGHLIGHT_PRE_TAG, HIGHLIGHT_POST_TAG } from './data/api'; +export { useGetBlockTypes } from './data/apiHooks'; export type { CollectionHit, ContentHit, ContentHitTags } from './data/api';