diff options
| author | Mohamed Bassem <me@mbassem.com> | 2026-02-08 15:53:14 +0000 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-02-08 15:53:14 +0000 |
| commit | b05a7531b76d580fc2378d3fed12f57e5f4b35b1 (patch) | |
| tree | c80d578507321ebe43f540649daba2bdec47f939 /apps/web/components/dashboard/search/useSearchAutocomplete.ts | |
| parent | 960ca9b67915408f26b825886f2b6c6481a658dc (diff) | |
| download | karakeep-b05a7531b76d580fc2378d3fed12f57e5f4b35b1.tar.zst | |
feat: add source filter to query language (#2465)
* feat: add source filter to query language
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* autocomplete source
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'apps/web/components/dashboard/search/useSearchAutocomplete.ts')
| -rw-r--r-- | apps/web/components/dashboard/search/useSearchAutocomplete.ts | 58 |
1 files changed, 57 insertions, 1 deletions
diff --git a/apps/web/components/dashboard/search/useSearchAutocomplete.ts b/apps/web/components/dashboard/search/useSearchAutocomplete.ts index 426e0835..f98f23f5 100644 --- a/apps/web/components/dashboard/search/useSearchAutocomplete.ts +++ b/apps/web/components/dashboard/search/useSearchAutocomplete.ts @@ -4,6 +4,7 @@ import type { LucideIcon } from "lucide-react"; import { useCallback, useMemo } from "react"; import { useQuery } from "@tanstack/react-query"; import { + Globe, History, ListTree, RssIcon, @@ -15,6 +16,7 @@ import { useBookmarkLists } from "@karakeep/shared-react/hooks/lists"; import { useTagAutocomplete } from "@karakeep/shared-react/hooks/tags"; import { useDebounce } from "@karakeep/shared-react/hooks/use-debounce"; import { useTRPC } from "@karakeep/shared-react/trpc"; +import { zBookmarkSourceSchema } from "@karakeep/shared/types/bookmarks"; const MAX_DISPLAY_SUGGESTIONS = 5; @@ -98,10 +100,14 @@ const QUALIFIER_DEFINITIONS = [ value: "age:", descriptionKey: "search.created_within", }, + { + value: "source:", + descriptionKey: "search.is_from_source", + }, ] satisfies ReadonlyArray<QualifierDefinition>; export interface AutocompleteSuggestionItem { - type: "token" | "tag" | "list" | "feed"; + type: "token" | "tag" | "list" | "feed" | "source"; id: string; label: string; insertText: string; @@ -398,6 +404,46 @@ const useListSuggestions = ( return listSuggestions; }; +const SOURCE_VALUES = zBookmarkSourceSchema.options; + +const useSourceSuggestions = ( + parsed: ParsedSearchState, +): AutocompleteSuggestionItem[] => { + const shouldSuggestSources = + parsed.normalizedTokenWithoutMinus.startsWith("source:"); + const sourceSearchTerm = shouldSuggestSources + ? parsed.normalizedTokenWithoutMinus.slice("source:".length) + : ""; + + const sourceSuggestions = useMemo<AutocompleteSuggestionItem[]>(() => { + if (!shouldSuggestSources) { + return []; + } + + return SOURCE_VALUES.filter((source) => { + if (sourceSearchTerm.length === 0) { + return true; + } + return source.startsWith(sourceSearchTerm); + }) + .slice(0, MAX_DISPLAY_SUGGESTIONS) + .map((source) => { + const insertText = `${parsed.isTokenNegative ? "-" : ""}source:${source}`; + return { + type: "source" as const, + id: `source-${source}`, + label: insertText, + insertText, + appendSpace: true, + description: undefined, + Icon: Globe, + } satisfies AutocompleteSuggestionItem; + }); + }, [shouldSuggestSources, sourceSearchTerm, parsed.isTokenNegative]); + + return sourceSuggestions; +}; + const useHistorySuggestions = ( value: string, history: string[], @@ -440,6 +486,7 @@ export const useSearchAutocomplete = ({ const tagSuggestions = useTagSuggestions(parsedState); const listSuggestions = useListSuggestions(parsedState); const feedSuggestions = useFeedSuggestions(parsedState); + const sourceSuggestions = useSourceSuggestions(parsedState); const historyItems = useHistorySuggestions(value, history); const { activeToken, getActiveToken } = parsedState; @@ -470,6 +517,14 @@ export const useSearchAutocomplete = ({ }); } + if (sourceSuggestions.length > 0) { + groups.push({ + id: "sources", + label: t("search.is_from_source"), + items: sourceSuggestions, + }); + } + // Only suggest qualifiers if no other suggestions are available if (groups.length === 0 && qualifierSuggestions.length > 0) { groups.push({ @@ -493,6 +548,7 @@ export const useSearchAutocomplete = ({ tagSuggestions, listSuggestions, feedSuggestions, + sourceSuggestions, historyItems, t, ]); |
