From 5adb918564a656483e007402ccf18e1a5fdfb36f Mon Sep 17 00:00:00 2001 From: Michael Schwobe Date: Tue, 12 Dec 2023 12:24:19 -0600 Subject: [PATCH] - Updated `/bookmarks/status` route with `defer`, `Await` and `Suspense` - Added `/bookmarks/status/all` route --- app/components/status-tr.tsx | 80 ++++++ .../table-columns-bookmarks-status.tsx | 154 ----------- app/routes/bookmarks.status._index.tsx | 243 ++++++++++++++++++ app/routes/bookmarks.status.all.tsx | 148 +++++++++++ app/routes/bookmarks.status.tsx | 175 ------------- app/utils/matches-validation.ts | 2 - app/utils/status.server.ts | 17 -- prisma/data.db | Bin 417792 -> 417792 bytes tests/e2e/bookmarks.status.test.ts | 15 +- 9 files changed, 472 insertions(+), 362 deletions(-) create mode 100644 app/components/status-tr.tsx delete mode 100644 app/components/table-columns-bookmarks-status.tsx create mode 100644 app/routes/bookmarks.status._index.tsx create mode 100644 app/routes/bookmarks.status.all.tsx delete mode 100644 app/routes/bookmarks.status.tsx diff --git a/app/components/status-tr.tsx b/app/components/status-tr.tsx new file mode 100644 index 0000000..dcf5373 --- /dev/null +++ b/app/components/status-tr.tsx @@ -0,0 +1,80 @@ +import { forwardRef } from "react"; +import { ButtonDelete } from "~/components/button-delete"; +import { StatusCode } from "~/components/status-code"; +import { StatusText } from "~/components/status-text"; +import { Icon } from "~/components/ui/icon"; +import { LinkButton } from "~/components/ui/link-button"; +import { Td, Tr } from "~/components/ui/table"; +import { cn } from "~/utils/misc"; +import type { GetStatusData } from "~/utils/status.server"; + +export const StatusTr = forwardRef< + React.ElementRef<"tr">, + Omit, "children"> & { + id: string; + isOkHidden?: boolean; + statusCode: GetStatusData["status"] | null; + statusText: GetStatusData["statusText"] | null; + url: string; + } +>( + ( + { className, id, isOkHidden, url, statusCode, statusText, ...props }, + ref, + ) => { + return ( + = 200 && + statusCode <= 299 + ? "hidden" + : undefined, + className, + )} + ref={ref} + > + + + + Edit bookmark + + + + {statusCode} + + + + + {url} + + + + {statusText} + + + + + + ); + }, +); +StatusTr.displayName = "StatusTr"; diff --git a/app/components/table-columns-bookmarks-status.tsx b/app/components/table-columns-bookmarks-status.tsx deleted file mode 100644 index 1261833..0000000 --- a/app/components/table-columns-bookmarks-status.tsx +++ /dev/null @@ -1,154 +0,0 @@ -import type { ColumnDef } from "@tanstack/react-table"; -import { createColumnHelper } from "@tanstack/react-table"; -import { ButtonDelete } from "~/components/button-delete"; -import { StatusCode } from "~/components/status-code"; -import { StatusText } from "~/components/status-text"; -import { Checkbox } from "~/components/ui/checkbox"; -import { Icon } from "~/components/ui/icon"; -import { LinkButton } from "~/components/ui/link-button"; -import type { loader as loaderBookmarksStatus } from "~/routes/bookmarks.status"; -import { cn } from "~/utils/misc"; - -type BookmarksStatusData = Awaited< - ReturnType>["json"]> ->["data"]; - -type BookmarksStatusItem = BookmarksStatusData[0]; - -const columnHelper = createColumnHelper(); - -// TODO: Remove ts-expect-error(s) once this is fixed. -// 🤷‍♂️ Flagged as a TS error and ts-expect-error doesn't work, leaving as is. -// See node module bug https://github.com/TanStack/table/issues/5135 -export const columnsBookmarksStatus: ColumnDef[] = [ - columnHelper.display({ - id: "select", - header: ({ table }) => ( - { - const handler = table.getToggleAllRowsSelectedHandler(); - return handler({ target: { checked } }); - }} - aria-label="Select all rows" - aria-controls={table - .getSelectedRowModel() - .rows.map((row) => row.original.id) - .join(" ")} - /> - ), - cell: ({ row }) => ( - { - const handler = row.getToggleSelectedHandler(); - return handler({ target: { checked } }); - }} - aria-label="Select row" - aria-controls={row.original.id} - /> - ), - footer: ({ column }) => column.id, - }), - - // @ts-expect-error - see comment above - columnHelper.accessor((row) => row._meta.status, { - id: "status", - sortingFn: "alphanumeric", - header: () => ( - <> - - Status - - ), - cell: ({ getValue }) => {getValue()}, - footer: ({ column }) => column.id, - }), - - // @ts-expect-error - see comment above - columnHelper.accessor("url", { - header: () => "URL", - cell: ({ getValue }) => ( - - - {getValue()} - - ), - footer: ({ column }) => column.id, - }), - - // @ts-expect-error - see comment above - columnHelper.accessor((row) => row._meta.statusText, { - id: "statusText", - sortingFn: "alphanumeric", - header: () => ( - <> - - 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", - enableSorting: false, - header: () => ( - <> - - Delete - - ), - cell: ({ getValue }) => ( - - ), - footer: ({ column }) => column.id, - }), -]; diff --git a/app/routes/bookmarks.status._index.tsx b/app/routes/bookmarks.status._index.tsx new file mode 100644 index 0000000..7e980b6 --- /dev/null +++ b/app/routes/bookmarks.status._index.tsx @@ -0,0 +1,243 @@ +import type { LoaderFunctionArgs, MetaFunction } from "@remix-run/node"; +import { defer } from "@remix-run/node"; +import { Await, useLoaderData } from "@remix-run/react"; +import { Suspense } from "react"; +import { ButtonFirst } from "~/components/button-first"; +import { ButtonLast } from "~/components/button-last"; +import { ButtonNext } from "~/components/button-next"; +import { ButtonPage } from "~/components/button-page"; +import { ButtonPrev } from "~/components/button-prev"; +import { FormPaginate } from "~/components/form-paginate"; +import { Main } from "~/components/main"; +import { SearchHelp } from "~/components/search-help"; +import { StatusTr } from "~/components/status-tr"; +import { Badge } from "~/components/ui/badge"; +import { H1 } from "~/components/ui/h1"; +import { Icon } from "~/components/ui/icon"; +import { LinkButton } from "~/components/ui/link-button"; +import { + Table, + TableWrapper, + Tbody, + Th, + Thead, + Tr, +} from "~/components/ui/table"; +import { + getBookmarksCount, + getBookmarksStatus, +} from "~/models/bookmark.server"; +import { requireUserId } from "~/utils/auth.server"; +import type { Handle } from "~/utils/matches-validation"; +import { formatMetaTitle } from "~/utils/misc"; +import { + toPaginationSearchParams, + toPaginationValues, +} from "~/utils/pagination"; +import { parsePaginationSearchParams } from "~/utils/pagination-validation"; +import type { GetStatusData } from "~/utils/status.server"; +import { getStatus } from "~/utils/status.server"; + +export const handle = { + /** + * This value is used to abort the fetch request after a certain delay. + * Why: It takes ~8s to resolve 20 items, but the default is 5s. + */ + abortDelay: 8_000, + /** + * This value disables the