diff --git a/apps/client/src/features/search/components/search-spotlight.tsx b/apps/client/src/features/search/components/search-spotlight.tsx index 8b41fa870..77d1cc293 100644 --- a/apps/client/src/features/search/components/search-spotlight.tsx +++ b/apps/client/src/features/search/components/search-spotlight.tsx @@ -106,7 +106,8 @@ export function SearchSpotlight({ spaceId }: SearchSpotlightProps) { } }, [aiSearchError, t]); - const isLabelBrowse = (filters.labelIds?.length ?? 0) > 0; + const isFilterBrowse = + (filters.labelIds?.length ?? 0) > 0 || !!filters.creatorId; // while the debounce is pending the empty list is not a settled "no results" const isQuerySettled = query === debouncedSearchQuery; @@ -231,11 +232,11 @@ export function SearchSpotlight({ spaceId }: SearchSpotlightProps) { ) : ( <> - {query.length === 0 && !isLabelBrowse && resultItems.length === 0 && ( + {query.length === 0 && !isFilterBrowse && resultItems.length === 0 && ( {t("Start typing to search...")} )} - {(query.length > 0 || isLabelBrowse) && + {(query.length > 0 || isFilterBrowse) && !isFetching && isQuerySettled && resultItems.length === 0 && ( @@ -244,7 +245,7 @@ export function SearchSpotlight({ spaceId }: SearchSpotlightProps) { {resultItems.length > 0 && <>{resultItems}} - {(query.length > 0 || isLabelBrowse) && isFetching && ( + {(query.length > 0 || isFilterBrowse) && isFetching && ( {t("Searching...")} diff --git a/apps/client/src/features/search/hooks/use-unified-search.ts b/apps/client/src/features/search/hooks/use-unified-search.ts index 500b2fd60..9270477b9 100644 --- a/apps/client/src/features/search/hooks/use-unified-search.ts +++ b/apps/client/src/features/search/hooks/use-unified-search.ts @@ -39,11 +39,16 @@ export function useUnifiedSearch( return await searchPage(backendParams); } }, - enabled: (!!params.query || (params.labelIds?.length ?? 0) > 0) && enabled, + enabled: + (!!params.query || + (params.labelIds?.length ?? 0) > 0 || + !!params.creatorId) && + enabled, // keep previous results only within the same search type; page results // rendered as attachments (or vice versa) crash on missing fields placeholderData: (previousData, previousQuery) => { - if (!params.query && !params.labelIds?.length) return undefined; + if (!params.query && !params.labelIds?.length && !params.creatorId) + return undefined; if (previousQuery && previousQuery.queryKey[1] !== searchType) { return undefined; } diff --git a/apps/server/src/core/search/search.service.ts b/apps/server/src/core/search/search.service.ts index 900f81729..ae0a2c13c 100644 --- a/apps/server/src/core/search/search.service.ts +++ b/apps/server/src/core/search/search.service.ts @@ -31,17 +31,19 @@ export class SearchService { ): Promise<{ items: SearchResponseDto[] }> { const query = searchParams.query?.trim() ?? ''; const labelIds = [...new Set(searchParams.labelIds ?? [])]; - // selected labels are browsable without a query - const browseByLabels = query.length < 1 && labelIds.length > 0; + // selected filters (labels, creator) are browsable without a query + const browseByFilters = + query.length < 1 && + (labelIds.length > 0 || Boolean(searchParams.creatorId)); - if (query.length < 1 && !browseByLabels) { + if (query.length < 1 && !browseByFilters) { return { items: [] }; } const searchQuery = tsquery(query + '*'); const titleOnly = searchParams.titleOnly === true; const titleQuery = query; - const rankColumn = browseByLabels + const rankColumn = browseByFilters ? sql`0`.as('rank') : titleOnly ? sql`word_similarity(lower(f_unaccent(${titleQuery})), lower(f_unaccent(pages.title)))`.as( @@ -50,7 +52,7 @@ export class SearchService { : sql`ts_rank(tsv, to_tsquery('english', f_unaccent(${searchQuery})))`.as( 'rank', ); - const highlightColumn = browseByLabels || titleOnly + const highlightColumn = browseByFilters || titleOnly ? sql`''`.as('highlight') : sql`ts_headline('english', text_content, to_tsquery('english', f_unaccent(${searchQuery})),'MinWords=9, MaxWords=10, MaxFragments=3')`.as( 'highlight', @@ -70,14 +72,14 @@ export class SearchService { rankColumn, highlightColumn, ]) - .$if(!browseByLabels && !titleOnly, (qb) => + .$if(!browseByFilters && !titleOnly, (qb) => qb.where( 'tsv', '@@', sql`to_tsquery('english', f_unaccent(${searchQuery}))`, ), ) - .$if(!browseByLabels && titleOnly, (qb) => + .$if(!browseByFilters && titleOnly, (qb) => qb.where((eb) => eb( sql`lower(f_unaccent(pages.title))`, @@ -100,8 +102,8 @@ export class SearchService { ), ) .where('deletedAt', 'is', null) - .$if(browseByLabels, (qb) => qb.orderBy('updatedAt', 'desc')) - .$if(!browseByLabels, (qb) => qb.orderBy('rank', 'desc')) + .$if(browseByFilters, (qb) => qb.orderBy('updatedAt', 'desc')) + .$if(!browseByFilters, (qb) => qb.orderBy('rank', 'desc')) .limit(searchParams.limit || 25) .offset(searchParams.offset || 0); diff --git a/apps/server/src/ee b/apps/server/src/ee index add0054e9..0be4a7617 160000 --- a/apps/server/src/ee +++ b/apps/server/src/ee @@ -1 +1 @@ -Subproject commit add0054e9640c089aaccdad9251c240b76e7053b +Subproject commit 0be4a761754f673f7453f0a4e295168d181824c3