diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-09-28 11:03:48 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-09-28 11:03:48 +0100 |
| commit | 62f7d900c52784ff05d933b52379e5455ea6bd00 (patch) | |
| tree | 2702d74c96576447974af84850f3ba6b66beeeb4 /packages/shared-react | |
| parent | 9fe09bfa9021c8d85d2d9aef591936101cab19f6 (diff) | |
| download | karakeep-62f7d900c52784ff05d933b52379e5455ea6bd00.tar.zst | |
feat: Add tag search and pagination (#1987)
* feat: Add tag search and use in the homepage
* use paginated query in the all tags view
* wire the load more buttons
* add skeleton to all tags page
* fix attachedby aggregation
* fix loading states
* fix hasNextPage
* use action buttons for load more buttons
* migrate the tags auto complete to the search api
* Migrate the tags editor to the new search API
* Replace tag merging dialog with tag auto completion
* Merge both search and list APIs
* fix tags.list
* add some tests for the endpoint
* add relevance based sorting
* change cursor
* update the REST API
* fix review comments
* more fixes
* fix lockfile
* i18n
* fix visible tags
Diffstat (limited to 'packages/shared-react')
| -rw-r--r-- | packages/shared-react/hooks/tags.ts | 35 | ||||
| -rw-r--r-- | packages/shared-react/hooks/use-debounce.ts | 17 |
2 files changed, 52 insertions, 0 deletions
diff --git a/packages/shared-react/hooks/tags.ts b/packages/shared-react/hooks/tags.ts index bbbe3d0e..f02ebc8f 100644 --- a/packages/shared-react/hooks/tags.ts +++ b/packages/shared-react/hooks/tags.ts @@ -1,5 +1,40 @@ +import { keepPreviousData } from "@tanstack/react-query"; + +import { ZTagListResponse } from "@karakeep/shared/types/tags"; + import { api } from "../trpc"; +export function usePaginatedSearchTags( + input: Parameters<typeof api.tags.list.useInfiniteQuery>[0], +) { + return api.tags.list.useInfiniteQuery(input, { + placeholderData: keepPreviousData, + getNextPageParam: (lastPage) => lastPage.nextCursor, + select: (data) => ({ + tags: data.pages.flatMap((page) => page.tags), + }), + gcTime: 60_000, + }); +} + +export function useTagAutocomplete<T>(opts: { + nameContains: string; + select?: (tags: ZTagListResponse) => T; +}) { + return api.tags.list.useQuery( + { + nameContains: opts.nameContains, + limit: 50, + sortBy: opts.nameContains ? "relevance" : "usage", + }, + { + select: opts.select, + placeholderData: keepPreviousData, + gcTime: opts.nameContains?.length > 0 ? 60_000 : 3_600_000, + }, + ); +} + export function useCreateTag( ...opts: Parameters<typeof api.tags.create.useMutation> ) { diff --git a/packages/shared-react/hooks/use-debounce.ts b/packages/shared-react/hooks/use-debounce.ts new file mode 100644 index 00000000..a973d774 --- /dev/null +++ b/packages/shared-react/hooks/use-debounce.ts @@ -0,0 +1,17 @@ +import React from "react"; + +export function useDebounce<T>(value: T, delayMs: number): T { + const [debouncedValue, setDebouncedValue] = React.useState<T>(value); + + React.useEffect(() => { + const handler = setTimeout(() => { + setDebouncedValue(value); + }, delayMs); + + return () => { + clearTimeout(handler); + }; + }, [value, delayMs]); + + return debouncedValue; +} |
