From 0c88231bf74ba582bbc7292a9164fabe66335818 Mon Sep 17 00:00:00 2001 From: Matt Aitken Date: Tue, 19 Nov 2024 12:09:43 +0000 Subject: [PATCH] Added some hidden routes to try PGLite out on --- .../route.tsx | 411 ++++++++++++++++++ .../route.tsx | 10 + 2 files changed, 421 insertions(+) create mode 100644 apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric._index/route.tsx create mode 100644 apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric/route.tsx diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric._index/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric._index/route.tsx new file mode 100644 index 000000000..04bfc34b2 --- /dev/null +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric._index/route.tsx @@ -0,0 +1,411 @@ +import { ArrowPathIcon, StopCircleIcon } from "@heroicons/react/20/solid"; +import { BeakerIcon, BookOpenIcon } from "@heroicons/react/24/solid"; +import { Form, useNavigation } from "@remix-run/react"; +import { LoaderFunctionArgs } from "@remix-run/server-runtime"; +import { IconCircleX } from "@tabler/icons-react"; +import { AnimatePresence, motion } from "framer-motion"; +import { ListChecks, ListX } from "lucide-react"; +import { Suspense, useState } from "react"; +import { TypedAwait, typeddefer, useTypedLoaderData } from "remix-typedjson"; +import { TaskIcon } from "~/assets/icons/TaskIcon"; +import { StepContentContainer } from "~/components/StepContentContainer"; +import { MainCenteredContainer, PageBody } from "~/components/layout/AppLayout"; +import { Button, LinkButton } from "~/components/primitives/Buttons"; +import { + Dialog, + DialogContent, + DialogDescription, + DialogFooter, + DialogHeader, + DialogTrigger, +} from "~/components/primitives/Dialog"; +import { Header1, Header2 } from "~/components/primitives/Headers"; +import { InfoPanel } from "~/components/primitives/InfoPanel"; +import { NavBar, PageAccessories, PageTitle } from "~/components/primitives/PageHeader"; +import { Paragraph } from "~/components/primitives/Paragraph"; +import { + SelectedItemsProvider, + useSelectedItems, +} from "~/components/primitives/SelectedItemsProvider"; +import { Spinner } from "~/components/primitives/Spinner"; +import { StepNumber } from "~/components/primitives/StepNumber"; +import { TextLink } from "~/components/primitives/TextLink"; +import { RunsFilters, TaskRunListSearchFilters } from "~/components/runs/v3/RunFilters"; +import { TaskRunsTable } from "~/components/runs/v3/TaskRunsTable"; +import { BULK_ACTION_RUN_LIMIT } from "~/consts"; +import { useOrganization } from "~/hooks/useOrganizations"; +import { useProject } from "~/hooks/useProject"; +import { useUser } from "~/hooks/useUser"; +import { findProjectBySlug } from "~/models/project.server"; +import { RunListPresenter } from "~/presenters/v3/RunListPresenter.server"; +import { requireUserId } from "~/services/session.server"; +import { cn } from "~/utils/cn"; +import { + docsPath, + ProjectParamSchema, + v3ProjectPath, + v3RunsPath, + v3TestPath, +} from "~/utils/pathBuilder"; +import { ListPagination } from "../../components/ListPagination"; +import { useEffect } from "react"; +import { pglite } from "~/pglite"; +import { PGliteWorker } from "@electric-sql/pglite/worker"; + +export default function Page() { + const project = useProject(); + + const [db, setDb] = useState(null); + + useEffect(() => { + const initDb = async () => { + const database = await pglite(); + setDb(database); + }; + + initDb(); + }, []); + + useEffect(() => { + const runQueries = async () => { + if (!db) return; + + // Run your queries here using db + // Example: + // const result = await db.query("SELECT * FROM table"); + }; + + runQueries(); + }, [db]); + + return ( + <> + + + + + Runs docs + + + + + + {({ selectedItems }) => ( +
+ +
+ + Loading runs +
+
+ } + > + {/* + {(list) => ( + <> + {list.runs.length === 0 && !list.hasFilters ? ( + list.possibleTasks.length === 0 ? ( + + ) : ( + + ) + ) : ( +
+
+ +
+ +
+
+ + +
+ )} + + )} +
*/} + + + + )} +
+
+ + ); +} + +function BulkActionBar() { + const { selectedItems, deselectAll } = useSelectedItems(); + const [barState, setBarState] = useState<"none" | "replay" | "cancel">("none"); + + const hasSelectedMaximum = selectedItems.size >= BULK_ACTION_RUN_LIMIT; + + return ( + + {selectedItems.size > 0 && ( + +
+ + Bulk actions: + {hasSelectedMaximum ? ( + + Maximum of {selectedItems.size} runs selected + + ) : ( + {selectedItems.size} runs selected + )} +
+
+ { + if (o) { + setBarState("cancel"); + } else { + setBarState("none"); + } + }} + /> + { + if (o) { + setBarState("replay"); + } else { + setBarState("none"); + } + }} + /> + +
+
+ )} +
+ ); +} + +function CancelRuns({ onOpen }: { onOpen: (open: boolean) => void }) { + const { selectedItems } = useSelectedItems(); + + const organization = useOrganization(); + const project = useProject(); + const failedRedirect = v3RunsPath(organization, project); + + const formAction = `/resources/taskruns/bulk/cancel`; + + const navigation = useNavigation(); + const isLoading = navigation.formAction === formAction; + + return ( + onOpen(o)}> + + + + + Cancel {selectedItems.size} runs? + + + Canceling these runs will stop them from running. Only runs that are not already + finished will be canceled, the others will remain in their existing state. + + + +
+ + + + {[...selectedItems].map((runId) => ( + + ))} + +
+
+
+
+ ); +} + +function ReplayRuns({ onOpen }: { onOpen: (open: boolean) => void }) { + const { selectedItems } = useSelectedItems(); + + const organization = useOrganization(); + const project = useProject(); + const failedRedirect = v3RunsPath(organization, project); + + const formAction = `/resources/taskruns/bulk/replay`; + + const navigation = useNavigation(); + const isLoading = navigation.formAction === formAction; + + return ( + onOpen(o)}> + + + + + Replay runs? + + + Replaying these runs will create a new run for each with the same payload and + environment as the original. It will use the latest version of the code for each task. + + + +
+ + + + {[...selectedItems].map((runId) => ( + + ))} + +
+
+
+
+ ); +} + +function CreateFirstTaskInstructions() { + const organization = useOrganization(); + const project = useProject(); + return ( + + + + Before running a task, you must first create one. Follow the instructions on the{" "} + Tasks page to create a + task, then return here to run it. + + + + ); +} + +function RunTaskInstructions() { + const organization = useOrganization(); + const project = useProject(); + return ( + + How to run your tasks + + + + You can perform a Run with any payload you want, or use one of our examples on the test + page. + + + Test + +
+
+ OR +
+
+
+ + + + + Performing a real run depends on the type of Trigger your Task is using. + + + How to run a task + + +
+ ); +} diff --git a/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric/route.tsx b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric/route.tsx new file mode 100644 index 000000000..f6723ddeb --- /dev/null +++ b/apps/webapp/app/routes/_app.orgs.$organizationSlug.projects.v3.$projectParam.runs.electric/route.tsx @@ -0,0 +1,10 @@ +import { Outlet } from "@remix-run/react"; +import { PageContainer } from "~/components/layout/AppLayout"; + +export default function Page() { + return ( + + + + ); +}