Skip to content

Commit

Permalink
feat(ui): Use server components for workflows page + add error/loadin…
Browse files Browse the repository at this point in the history
…g pages
  • Loading branch information
daryllimyt committed Mar 10, 2024
1 parent 9bd13e0 commit 6de4f69
Show file tree
Hide file tree
Showing 5 changed files with 167 additions and 140 deletions.
17 changes: 17 additions & 0 deletions frontend/src/app/workflows/[id]/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { Skeleton } from "@/components/ui/skeleton"

export default function Loading() {
return (
<div className="grid h-full grid-cols-12">
<div className="col-span-1">
<Skeleton className="h-full w-full" />
</div>
<div className="col-span-8">
<Skeleton className="h-full w-full bg-transparent" />
</div>
<div className="col-span-3">
<Skeleton className="h-full w-full" />
</div>
</div>
)
}
25 changes: 25 additions & 0 deletions frontend/src/app/workflows/error.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
"use client"

// Error components must be Client Components
import { useEffect } from "react"

import { AlertDestructive } from "@/components/alert-destructive"

export default function Error({
error,
reset,
}: {
error: Error & { digest?: string }
reset: () => void
}) {
useEffect(() => {
// Log the error to an error reporting service
console.error(error)
}, [error])

return (
<main className="container flex h-full w-full max-w-[400px] items-center justify-center">
<AlertDestructive message={error.message} reset={reset} />
</main>
)
}
9 changes: 9 additions & 0 deletions frontend/src/app/workflows/loading.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Loader2 } from "lucide-react"

export default function Loading() {
return (
<div className="container flex h-full max-w-[800px] flex-col justify-center space-y-2 p-16">
<Loader2 className="mx-auto animate-spin text-gray-500" />
</div>
)
}
150 changes: 10 additions & 140 deletions frontend/src/app/workflows/page.tsx
Original file line number Diff line number Diff line change
@@ -1,147 +1,17 @@
"use client"

import React from "react"
import Link from "next/link"
import { useSessionContext } from "@/providers/session"
import { useQuery } from "@tanstack/react-query"
import { PlusCircle } from "lucide-react"
import { redirect } from "next/navigation"
import { createClient } from "@/utils/supabase/server"

import { WorkflowMetadata } from "@/types/schemas"
import { fetchAllWorkflows } from "@/lib/flow"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Skeleton } from "@/components/ui/skeleton"
import {
NewWorkflowDialog,
NewWorkflowDialogTrigger,
} from "@/components/new-workflow-dialog"
import NoSSR from "@/components/no-ssr"
import { WorkflowsDashboard } from "./workflows-dashboard"

export default function Page() {
return (
<NoSSR>
<WorkflowsPage suppressHydrationWarning />
</NoSSR>
)
}
function WorkflowsPage(props: React.HTMLAttributes<HTMLElement>) {
const { session, isLoading: sessionIsLoading } = useSessionContext()
export default async function Page() {
const supabase = createClient()

const {
data: userWorkflows,
isLoading,
error,
} = useQuery<WorkflowMetadata[], Error>({
queryKey: ["workflows"],
queryFn: async () => {
if (!session) {
console.error("Invalid session")
throw new Error("Invalid session")
}
console.log(session)
const workflows = await fetchAllWorkflows(session)
return workflows
},
})

if (sessionIsLoading) {
return (
<div
className="container flex h-full w-full flex-col items-center justify-center space-y-4"
{...props}
>
<Skeleton className="h-20 w-96" />
<Skeleton className="h-20 w-96" />
<Skeleton className="h-20 w-96" />
<Skeleton className="h-20 w-96" />
<Skeleton className="h-20 w-96" />
</div>
)
data: { session },
} = await supabase.auth.getSession()
if (!session) {
redirect("/login")
}
if (error) {
throw new Error("Error fetching workflows")
}

return (
<div className="container flex h-full max-w-[800px] flex-col justify-center space-y-2 p-16">
<div className="flex w-full ">
<div className="items-start space-y-2 text-left">
<h2 className="text-2xl font-bold tracking-tight">Workflows</h2>
<p className="text-md text-muted-foreground">
Welcome back! Here&apos;s a list of your workflows.
</p>
</div>

<NewWorkflowDialog>
<NewWorkflowDialogTrigger asChild>
<Button
variant="outline"
role="combobox"
className="ml-auto space-x-2"
onClick={() => {
console.log("Create new workflow")
}}
>
<PlusCircle className="mr-2 h-4 w-4" />
New
</Button>
</NewWorkflowDialogTrigger>
</NewWorkflowDialog>
</div>
{isLoading ? (
<Skeleton className="h-20 w-full" />
) : (
<WorkflowList workflows={userWorkflows ?? []} />
)}
</div>
)
}

interface WorkflowListProps {
workflows: WorkflowMetadata[]
}

export function WorkflowList({ workflows }: WorkflowListProps) {
return (
<div className="flex flex-col gap-2 pt-4">
{workflows.length === 0 ? (
<span className="my-4">No workflows created.</span>
) : (
<>
{workflows.map((wf) => (
<Link
key={wf.id}
href={`/workflows/${wf.id}`}
className={cn(
"flex min-h-24 min-w-[600px] flex-col items-start justify-start rounded-lg border p-6 text-left text-sm shadow-md transition-all hover:bg-accent",
"dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white"
)}
>
<div className="flex w-full flex-col gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold capitalize">{wf.title}</div>
</div>
<div className="ml-auto flex items-center space-x-2">
<span
className={cn(
"flex h-2 w-2 rounded-full ",
wf.status === "online" ? "bg-green-400" : "bg-gray-400"
)}
/>
<span className="text-xs text-muted-foreground">
Last run: 2 hours ago
</span>
</div>
</div>
<div className="text-xs font-medium text-muted-foreground">
{wf.description ?? ""}
</div>
</div>
</Link>
))}
</>
)}
</div>
)
return <WorkflowsDashboard session={session} />
}
106 changes: 106 additions & 0 deletions frontend/src/app/workflows/workflows-dashboard.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
import { Suspense } from "react"
import Link from "next/link"
import { type Session } from "@supabase/supabase-js"
import { PlusCircle } from "lucide-react"

import { fetchAllWorkflows } from "@/lib/flow"
import { cn } from "@/lib/utils"
import { Button } from "@/components/ui/button"
import { Skeleton } from "@/components/ui/skeleton"
import {
NewWorkflowDialog,
NewWorkflowDialogTrigger,
} from "@/components/new-workflow-dialog"

interface WorkflowsDashboardProps extends React.HTMLAttributes<HTMLElement> {
session: Session
}

export async function WorkflowsDashboard({ session }: WorkflowsDashboardProps) {
return (
<div className="container flex h-full max-w-[800px] flex-col space-y-4 p-16">
<div className="flex w-full pt-16">
<div className="items-start space-y-2 text-left">
<h2 className="text-2xl font-bold tracking-tight">Workflows</h2>
<p className="text-md text-muted-foreground">
Welcome back! Here&apos;s a list of your workflows.
</p>
</div>
<NewWorkflowDialog>
<NewWorkflowDialogTrigger asChild>
<Button
variant="outline"
role="combobox"
className="ml-auto space-x-2"
>
<PlusCircle className="mr-2 h-4 w-4" />
New
</Button>
</NewWorkflowDialogTrigger>
</NewWorkflowDialog>
</div>
<Suspense
fallback={
<div className="flex flex-col gap-2 pt-4">
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
<Skeleton className="h-24 w-full" />
</div>
}
>
<WorkflowList session={session} />
</Suspense>
</div>
)
}

interface WorkflowListProps {
session: Session
}

export async function WorkflowList({ session }: WorkflowListProps) {
const workflows = await fetchAllWorkflows(session)
return (
<div className="flex flex-col gap-2 pt-4">
{workflows.length === 0 ? (
<span className="my-4">No workflows created.</span>
) : (
<>
{workflows.map((wf) => (
<Link
key={wf.id}
href={`/workflows/${wf.id}`}
className={cn(
"flex min-h-24 min-w-[600px] flex-col items-start justify-start rounded-lg border p-6 text-left text-sm shadow-md transition-all hover:bg-accent",
"dark:bg-muted dark:text-white dark:hover:bg-muted dark:hover:text-white"
)}
>
<div className="flex w-full flex-col gap-1">
<div className="flex items-center">
<div className="flex items-center gap-2">
<div className="font-semibold capitalize">{wf.title}</div>
</div>
<div className="ml-auto flex items-center space-x-2">
<span
className={cn(
"flex h-2 w-2 rounded-full ",
wf.status === "online" ? "bg-green-400" : "bg-gray-400"
)}
/>
<span className="text-xs text-muted-foreground">
Last run: 2 hours ago
</span>
</div>
</div>
<div className="text-xs font-medium text-muted-foreground">
{wf.description ?? ""}
</div>
</div>
</Link>
))}
</>
)}
</div>
)
}

0 comments on commit 6de4f69

Please sign in to comment.