diff options
| author | Mohamed Bassem <me@mbassem.com> | 2025-01-12 23:47:25 +0000 |
|---|---|---|
| committer | Mohamed Bassem <me@mbassem.com> | 2025-01-12 23:47:25 +0000 |
| commit | 38d403bcc26244e778a6e7a2f75ee39a9ec7ed27 (patch) | |
| tree | 192d990e67a0b95aece9381a149513d14f6b0464 /apps/web/components | |
| parent | 9fd26b472b18924ab11afcebace90329b0fe3abf (diff) | |
| download | karakeep-38d403bcc26244e778a6e7a2f75ee39a9ec7ed27.tar.zst | |
fix: Limit concurrency of bulk actions. Fix #773
Diffstat (limited to 'apps/web/components')
3 files changed, 59 insertions, 30 deletions
diff --git a/apps/web/components/dashboard/BulkBookmarksAction.tsx b/apps/web/components/dashboard/BulkBookmarksAction.tsx index eb0e0cec..9d5ecdbe 100644 --- a/apps/web/components/dashboard/BulkBookmarksAction.tsx +++ b/apps/web/components/dashboard/BulkBookmarksAction.tsx @@ -27,12 +27,15 @@ import { useRecrawlBookmark, useUpdateBookmark, } from "@hoarder/shared-react/hooks/bookmarks"; +import { limitConcurrency } from "@hoarder/shared/concurrency"; import { BookmarkTypes } from "@hoarder/shared/types/bookmarks"; import BulkManageListsModal from "./bookmarks/BulkManageListsModal"; import BulkTagModal from "./bookmarks/BulkTagModal"; import { ArchivedActionIcon, FavouritedActionIcon } from "./bookmarks/icons"; +const MAX_CONCURRENT_BULK_ACTIONS = 50; + export default function BulkBookmarksAction() { const { t } = useTranslation(); const { selectedBookmarks, isBulkEditEnabled } = useBulkActionsStore(); @@ -100,11 +103,15 @@ export default function BulkBookmarksAction() { (item) => item.content.type === BookmarkTypes.LINK, ); await Promise.all( - links.map((item) => - recrawlBookmarkMutator.mutateAsync({ - bookmarkId: item.id, - archiveFullPage, - }), + limitConcurrency( + links.map( + (item) => () => + recrawlBookmarkMutator.mutateAsync({ + bookmarkId: item.id, + archiveFullPage, + }), + ), + MAX_CONCURRENT_BULK_ACTIONS, ), ); toast({ @@ -145,12 +152,16 @@ export default function BulkBookmarksAction() { archived, }: UpdateBookmarkProps) => { await Promise.all( - selectedBookmarks.map((item) => - updateBookmarkMutator.mutateAsync({ - bookmarkId: item.id, - favourited, - archived, - }), + limitConcurrency( + selectedBookmarks.map( + (item) => () => + updateBookmarkMutator.mutateAsync({ + bookmarkId: item.id, + favourited, + archived, + }), + ), + MAX_CONCURRENT_BULK_ACTIONS, ), ); toast({ @@ -160,8 +171,12 @@ export default function BulkBookmarksAction() { const deleteBookmarks = async () => { await Promise.all( - selectedBookmarks.map((item) => - deleteBookmarkMutator.mutateAsync({ bookmarkId: item.id }), + limitConcurrency( + selectedBookmarks.map( + (item) => () => + deleteBookmarkMutator.mutateAsync({ bookmarkId: item.id }), + ), + MAX_CONCURRENT_BULK_ACTIONS, ), ); toast({ diff --git a/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx b/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx index 9c1f05d2..27e5c5e2 100644 --- a/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx +++ b/apps/web/components/dashboard/bookmarks/BulkManageListsModal.tsx @@ -21,6 +21,7 @@ import { useForm } from "react-hook-form"; import { z } from "zod"; import { useAddBookmarkToList } from "@hoarder/shared-react/hooks/lists"; +import { limitConcurrency } from "@hoarder/shared/concurrency"; import { BookmarkListSelector } from "../lists/BookmarkListSelector"; @@ -67,11 +68,15 @@ export default function BulkManageListsModal({ const onSubmit = async (value: z.infer<typeof formSchema>) => { const results = await Promise.allSettled( - bookmarkIds.map((bookmarkId) => - addToList({ - bookmarkId, - listId: value.listId, - }), + limitConcurrency( + bookmarkIds.map( + (bookmarkId) => () => + addToList({ + bookmarkId, + listId: value.listId, + }), + ), + 50, ), ); diff --git a/apps/web/components/dashboard/bookmarks/BulkTagModal.tsx b/apps/web/components/dashboard/bookmarks/BulkTagModal.tsx index 3c8e75e7..03af9e11 100644 --- a/apps/web/components/dashboard/bookmarks/BulkTagModal.tsx +++ b/apps/web/components/dashboard/bookmarks/BulkTagModal.tsx @@ -11,6 +11,7 @@ import { toast } from "@/components/ui/use-toast"; import { useUpdateBookmarkTags } from "@hoarder/shared-react/hooks/bookmarks"; import { api } from "@hoarder/shared-react/trpc"; +import { limitConcurrency } from "@hoarder/shared/concurrency"; import { ZBookmark } from "@hoarder/shared/types/bookmarks"; import { TagsEditor } from "./TagsEditor"; @@ -59,12 +60,16 @@ export default function BulkTagModal({ const onAttach = async (tag: { tagName: string; tagId?: string }) => { const results = await Promise.allSettled( - bookmarkIds.map((id) => - mutateAsync({ - bookmarkId: id, - attach: [tag], - detach: [], - }), + limitConcurrency( + bookmarkIds.map( + (id) => () => + mutateAsync({ + bookmarkId: id, + attach: [tag], + detach: [], + }), + ), + 50, ), ); const successes = results.filter((r) => r.status == "fulfilled").length; @@ -81,12 +86,16 @@ export default function BulkTagModal({ tagName: string; }) => { const results = await Promise.allSettled( - bookmarkIds.map((id) => - mutateAsync({ - bookmarkId: id, - attach: [], - detach: [{ tagId }], - }), + limitConcurrency( + bookmarkIds.map( + (id) => () => + mutateAsync({ + bookmarkId: id, + attach: [], + detach: [{ tagId }], + }), + ), + 50, ), ); const successes = results.filter((r) => r.status == "fulfilled").length; |
