From 705d539c8e9c6a86882825ee4dabeff3027ba827 Mon Sep 17 00:00:00 2001 From: Mohamed Bassem Date: Sat, 30 Nov 2024 19:12:45 +0000 Subject: feature: Store crawling status code and allow users to find broken links. Fixes #169 --- apps/web/app/settings/broken-links/page.tsx | 131 ++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 apps/web/app/settings/broken-links/page.tsx (limited to 'apps/web/app/settings') diff --git a/apps/web/app/settings/broken-links/page.tsx b/apps/web/app/settings/broken-links/page.tsx new file mode 100644 index 00000000..0b83dfa9 --- /dev/null +++ b/apps/web/app/settings/broken-links/page.tsx @@ -0,0 +1,131 @@ +"use client"; + +import { ActionButton } from "@/components/ui/action-button"; +import { FullPageSpinner } from "@/components/ui/full-page-spinner"; +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table"; +import { toast } from "@/components/ui/use-toast"; +import { RefreshCw, Trash2 } from "lucide-react"; +import { useTranslation } from "react-i18next"; + +import { + useDeleteBookmark, + useRecrawlBookmark, +} from "@hoarder/shared-react/hooks/bookmarks"; +import { api } from "@hoarder/shared-react/trpc"; + +export default function BrokenLinksPage() { + const { t } = useTranslation(); + + const apiUtils = api.useUtils(); + const { data, isPending } = api.bookmarks.getBrokenLinks.useQuery(); + + const { mutate: deleteBookmark, isPending: isDeleting } = useDeleteBookmark({ + onSuccess: () => { + toast({ + description: t("toasts.bookmarks.deleted"), + }); + apiUtils.bookmarks.getBrokenLinks.invalidate(); + }, + onError: () => { + toast({ + description: t("common.something_went_wrong"), + variant: "destructive", + }); + }, + }); + + const { mutate: recrawlBookmark, isPending: isRecrawling } = + useRecrawlBookmark({ + onSuccess: () => { + toast({ + description: t("toasts.bookmarks.refetch"), + }); + apiUtils.bookmarks.getBrokenLinks.invalidate(); + }, + onError: () => { + toast({ + description: t("common.something_went_wrong"), + variant: "destructive", + }); + }, + }); + + return ( +
+
+
+ {t("settings.broken_links.broken_links")} +
+
+
+ {isPending && } + {!isPending && data && data.bookmarks.length == 0 && ( +

+ No broken links found +

+ )} + {!isPending && data && data.bookmarks.length > 0 && ( + + + + {t("common.url")} + {t("common.created_at")} + + {t("settings.broken_links.last_crawled_at")} + + + {t("settings.broken_links.crawling_status")} + + {t("common.action")} + + + + {data.bookmarks.map((b) => ( + + {b.url} + {b.createdAt?.toLocaleString()} + {b.crawledAt?.toLocaleString()} + + {b.isCrawlingFailure ? ( + Failed + ) : ( + b.statusCode + )} + + + recrawlBookmark({ bookmarkId: b.id })} + className="flex items-center gap-2" + > + + {t("actions.recrawl")} + + deleteBookmark({ bookmarkId: b.id })} + loading={isDeleting} + className="flex items-center gap-2" + > + + {t("actions.delete")} + + + + ))} + + +
+ )} +
+
+ ); +} -- cgit v1.2.3-70-g09d2