From 62f7d900c52784ff05d933b52379e5455ea6bd00 Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sun, 28 Sep 2025 11:03:48 +0100 Subject: 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 --- apps/cli/src/commands/dump.ts | 17 ++++++++++++++--- apps/cli/src/commands/migrate.ts | 4 ++-- apps/cli/src/commands/tags.ts | 2 +- 3 files changed, 17 insertions(+), 6 deletions(-) (limited to 'apps/cli') diff --git a/apps/cli/src/commands/dump.ts b/apps/cli/src/commands/dump.ts index 5f3f8f5e..6f473182 100644 --- a/apps/cli/src/commands/dump.ts +++ b/apps/cli/src/commands/dump.ts @@ -12,6 +12,7 @@ import type { ZBookmark } from "@karakeep/shared/types/bookmarks"; import type { ZBookmarkList } from "@karakeep/shared/types/lists"; import { MAX_NUM_BOOKMARKS_PER_PAGE } from "@karakeep/shared/types/bookmarks"; import { ZCursor } from "@karakeep/shared/types/pagination"; +import { MAX_NUM_TAGS_PER_PAGE } from "@karakeep/shared/types/tags"; const OK = chalk.green("✓"); const FAIL = chalk.red("✗"); @@ -191,9 +192,19 @@ export const dumpCmd = new Command() // 3) Tags if (!opts.excludeTags) { stepStart("Exporting tags"); - const { tags } = await api.tags.list.query(); - await writeJson(path.join(workRoot, "tags", "index.json"), tags); - manifest.counts.tags = tags.length; + + let cursor = null; + let allTags = []; + do { + const { tags, nextCursor } = await api.tags.list.query({ + limit: MAX_NUM_TAGS_PER_PAGE, + cursor, + }); + allTags.push(...tags); + cursor = nextCursor; + } while (cursor); + await writeJson(path.join(workRoot, "tags", "index.json"), allTags); + manifest.counts.tags = allTags.length; stepEndSuccess(); } diff --git a/apps/cli/src/commands/migrate.ts b/apps/cli/src/commands/migrate.ts index 750daf61..ee0d85c8 100644 --- a/apps/cli/src/commands/migrate.ts +++ b/apps/cli/src/commands/migrate.ts @@ -490,7 +490,7 @@ async function migrateTags( onProgress?: (ensured: number, total: number) => void, ) { try { - const { tags: srcTags } = await src.tags.list.query(); + const { tags: srcTags } = await src.tags.list.query({}); // Create tags by name; ignore if exist let ensured = 0; for (const t of srcTags) { @@ -503,7 +503,7 @@ async function migrateTags( onProgress?.(ensured, srcTags.length); } // Build id map using destination's current tags - const { tags: destTags } = await dest.tags.list.query(); + const { tags: destTags } = await dest.tags.list.query({}); const nameToDestId = destTags.reduce>((acc, t) => { acc[t.name] = t.id; return acc; diff --git a/apps/cli/src/commands/tags.ts b/apps/cli/src/commands/tags.ts index 14cb7f10..b15fef90 100644 --- a/apps/cli/src/commands/tags.ts +++ b/apps/cli/src/commands/tags.ts @@ -20,7 +20,7 @@ tagsCmd const api = getAPIClient(); try { - const tags = (await api.tags.list.query()).tags; + const tags = (await api.tags.list.query({})).tags; tags.sort((a, b) => b.numBookmarks - a.numBookmarks); if (getGlobalOptions().json) { printObject(tags); -- cgit v1.2.3-70-g09d2