From 62a0289c7132d0f5c8951a8ebf146db7fa3ba67b Mon Sep 17 00:00:00 2001 From: Michael Schwobe Date: Mon, 11 Dec 2023 17:51:07 -0600 Subject: [PATCH] Enhance bookmarks status call flexibility: - Added `getBookmarksCount` function - Added optional `skip` and `take` params to the `getBookmarksStatus` function - Updated loader to use `Promise.all` - Updated `getStatus` with better error responses - Updated `StatusText` with truncation styles --- app/components/status-text.tsx | 9 +++++- .../table-columns-bookmarks-status.tsx | 29 +++++++++++++++++-- app/models/bookmark.server.ts | 18 +++++++++++- app/routes/bookmarks._index.tsx | 6 ++-- app/routes/bookmarks.status.tsx | 18 ++++++++---- app/utils/status.server.ts | 7 +++-- 6 files changed, 71 insertions(+), 16 deletions(-) diff --git a/app/components/status-text.tsx b/app/components/status-text.tsx index e4ad0a1..d880e91 100644 --- a/app/components/status-text.tsx +++ b/app/components/status-text.tsx @@ -6,7 +6,14 @@ export const StatusText = forwardRef< React.ComponentPropsWithoutRef<"span"> >(({ children, className, ...props }, ref) => { return ( - + {typeof children === "string" ? children : "Pending"} ); diff --git a/app/components/table-columns-bookmarks-status.tsx b/app/components/table-columns-bookmarks-status.tsx index 60f6a8f..1261833 100644 --- a/app/components/table-columns-bookmarks-status.tsx +++ b/app/components/table-columns-bookmarks-status.tsx @@ -80,8 +80,8 @@ export const columnsBookmarksStatus: ColumnDef[] = [ to={getValue()} target="_blank" rel="noopener noreferrer" - variant="ghost" size="sm" + variant="ghost" className={cn( "flex w-full justify-start overflow-hidden", "max-w-[75vw] sm:max-w-[45vw]", @@ -101,13 +101,36 @@ export const columnsBookmarksStatus: ColumnDef[] = [ header: () => ( <> - Cause + Status Text ), cell: ({ getValue }) => {getValue()}, footer: ({ column }) => column.id, }), + // @ts-expect-error - see comment above + columnHelper.accessor("id", { + id: "edit", + enableSorting: false, + header: () => ( + <> + + Edit + + ), + cell: ({ getValue }) => ( + + + Edit bookmark + + ), + footer: ({ column }) => column.id, + }), + // @ts-expect-error - see comment above columnHelper.accessor("id", { id: "delete", @@ -122,8 +145,8 @@ export const columnsBookmarksStatus: ColumnDef[] = [ ), footer: ({ column }) => column.id, diff --git a/app/models/bookmark.server.ts b/app/models/bookmark.server.ts index 7e248f6..33d8ffc 100644 --- a/app/models/bookmark.server.ts +++ b/app/models/bookmark.server.ts @@ -69,6 +69,14 @@ export async function getBookmarks({ }); } +/** + * If changing this, also double-check the same value in: + * - `/app/routes/bookmarks.status.tsx` + */ +export async function getBookmarksCount() { + return await prisma.bookmark.count(); +} + /** * If changing this, also double-check the same value in: * - `/app/utils/bookmark-exports.server.ts` @@ -96,10 +104,18 @@ export async function getBookmarksLatest({ take = 3 }: { take?: number } = {}) { * If changing this, also double-check the same value in: * - `/app/routes/bookmarks.status.tsx` */ -export async function getBookmarksStatus() { +export async function getBookmarksStatus({ + skip, + take, +}: { + skip?: number | null; + take?: number | null; +} = {}) { return await prisma.bookmark.findMany({ select: { id: true, url: true }, orderBy: [{ createdAt: "desc" }, { url: "asc" }], + ...(take ? { take } : {}), + ...(skip ? { skip } : {}), }); } diff --git a/app/routes/bookmarks._index.tsx b/app/routes/bookmarks._index.tsx index fb1b1fa..b6ff80e 100644 --- a/app/routes/bookmarks._index.tsx +++ b/app/routes/bookmarks._index.tsx @@ -48,6 +48,9 @@ export async function loader({ request }: LoaderFunctionArgs) { const count = bookmarks.length; const data = await getFavicons(bookmarks.slice(skip, skip + take)); + const hasData = data.length > 0; + const hasPagination = count > take; + const paginationSearchParams = toPaginationSearchParams({ searchParams, take, @@ -58,8 +61,6 @@ export async function loader({ request }: LoaderFunctionArgs) { take, total: count, }); - const hasData = data.length > 0; - const hasPagination = count > take; return json({ count, @@ -109,6 +110,7 @@ export default function BookmarksIndexPage() { Bookmarks status diff --git a/app/routes/bookmarks.status.tsx b/app/routes/bookmarks.status.tsx index abbf966..8a50ded 100644 --- a/app/routes/bookmarks.status.tsx +++ b/app/routes/bookmarks.status.tsx @@ -15,7 +15,10 @@ import { TableSelectable } from "~/components/table-selectable"; import { Badge } from "~/components/ui/badge"; import { H1 } from "~/components/ui/h1"; import { Icon } from "~/components/ui/icon"; -import { getBookmarksStatus } from "~/models/bookmark.server"; +import { + getBookmarksCount, + getBookmarksStatus, +} from "~/models/bookmark.server"; import { requireUserId } from "~/utils/auth.server"; import { cn, formatMetaTitle } from "~/utils/misc"; import { @@ -31,14 +34,19 @@ export async function loader({ request }: LoaderFunctionArgs) { const { searchParams } = new URL(request.url); const { skip, take } = parsePaginationSearchParams({ searchParams }); - const bookmarks = await getBookmarksStatus(); - const count = bookmarks.length; - const data = await getStatuses(bookmarks.slice(skip, skip + take), 60000 * 2); + const [bookmarks, count] = await Promise.all([ + getBookmarksStatus({ skip, take }), + getBookmarksCount(), + ]); + const data = await getStatuses(bookmarks, 5_000); const countOk = data.filter((el) => el._meta.ok).length; const countNotOk = Math.abs(data.length - countOk); const risk = countNotOk > 5 ? 2 : countNotOk > 0 ? 1 : 0; + const hasData = data.length > 0; + const hasPagination = count > take; + const paginationSearchParams = toPaginationSearchParams({ searchParams, take, @@ -49,8 +57,6 @@ export async function loader({ request }: LoaderFunctionArgs) { take, total: count, }); - const hasData = data.length > 0; - const hasPagination = count > take; return json({ count, diff --git a/app/utils/status.server.ts b/app/utils/status.server.ts index 3419565..dd36614 100644 --- a/app/utils/status.server.ts +++ b/app/utils/status.server.ts @@ -6,17 +6,18 @@ export async function getStatus(input: string, timeout: number) { method: "HEAD", signal: AbortSignal.timeout(timeout), }); - return { ok, status, statusText }; + const message = statusText.length > 0 ? statusText : undefined; + return { ok, status, statusText: message ?? "Unknown" }; } catch (error) { if (error instanceof Error) { const name = error.name.length > 0 ? error.name : undefined; const message = error.message.length > 0 ? error.message : undefined; const status = name === "TimeoutError" ? 408 : name === "AbortError" ? 504 : 500; - const statusText = name ?? message ?? "Unknown Error"; + const statusText = name ?? message ?? "Unknown"; return { ok: false, status, statusText }; } else { - return { ok: false, status: 500, statusText: "Uncaught Error" }; + return { ok: false, status: 500, statusText: "Uncaught" }; } } }