# Workflow runs

> The latest workflow runs with their status, which update while a run is in progress.

- Block: [workflows](https://bettersupabase.com/blocks/workflows.md)
- Kind: component
- Hook: `useWorkflowRuns` from `better-supabase/blocks/workflows/react`
- Page: https://bettersupabase.com/recipes/workflow-runs

## Install the block

```bash
npx better-supabase add workflows
```

## Web (Next.js)

Add the shadcn components:

```bash
npx shadcn add badge empty skeleton table
```

From `apps/examples/nextjs/src/features/workflows/components/workflow-runs.tsx` (https://github.com/ScaleDockHQ/better-supabase/blob/main/apps/examples/nextjs/src/features/workflows/components/workflow-runs.tsx):

```tsx
"use client";

import { useWorkflowRuns } from "better-supabase/blocks/workflows/react";
import { WorkflowIcon } from "lucide-react";
import { useExtracted, useFormatter } from "next-intl";

import { Badge } from "@/components/ui/badge";
import {
  Empty,
  EmptyDescription,
  EmptyHeader,
  EmptyMedia,
  EmptyTitle,
} from "@/components/ui/empty";
import { Skeleton } from "@/components/ui/skeleton";
import {
  Table,
  TableBody,
  TableCell,
  TableHead,
  TableHeader,
  TableRow,
} from "@/components/ui/table";
import { Link } from "@/i18n/navigation";

import { statusVariant, workflowName } from "../workflow-labels";

/**
 * The organization's runs from the workflows block, loaded again when a
 * run changes status (`workflow-runs:<tenant>`).
 */
export function WorkflowRuns({ tenant }: { tenant: string | null }) {
  const t = useExtracted("workflows");
  const format = useFormatter();

  const { runs, status } = useWorkflowRuns({
    tenant,
    schema: "api",
    limit: 50,
  });

  if (runs === undefined) {
    return <WorkflowRunsSkeleton />;
  }

  if (runs.length === 0) {
    return (
      <Empty className="border">
        <EmptyHeader>
          <EmptyMedia variant="icon">
            <WorkflowIcon />
          </EmptyMedia>
          <EmptyTitle>{t("No runs yet")}</EmptyTitle>
          <EmptyDescription>
            {t("Start a sample workflow to see its run here.")}
          </EmptyDescription>
        </EmptyHeader>
      </Empty>
    );
  }

  return (
    <div
      className="rounded-xl border"
      data-testid="workflow-runs"
      data-status={status}
    >
      <Table>
        <TableHeader>
          <TableRow>
            <TableHead>{t("Workflow")}</TableHead>
            <TableHead>{t("Status")}</TableHead>
            <TableHead className="text-right">{t("Started")}</TableHead>
          </TableRow>
        </TableHeader>
        <TableBody>
          {runs.map((run) => (
            <TableRow key={run.id}>
              <TableCell>
                <Link href={`/workflows/${run.id}`} className="font-medium">
                  {workflowName(run.definition)}
                </Link>
              </TableCell>
              <TableCell>
                <Badge variant={statusVariant(run.status)}>{run.status}</Badge>
              </TableCell>
              <TableCell className="text-right text-xs text-muted-foreground tabular-nums">
                {format.dateTime(new Date(run.createdAt.epochMilliseconds), {
                  dateStyle: "medium",
                  timeStyle: "short",
                })}
              </TableCell>
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </div>
  );
}

export function WorkflowRunsSkeleton() {
  return (
    <div className="space-y-2" aria-busy="true">
      {Array.from({ length: 4 }, (_, index) => (
        <Skeleton key={index} className="h-11 w-full" />
      ))}
    </div>
  );
}
```

## Prompt

Paste this into a coding agent to build the recipe in your app.

### Web

```text
Build "Workflow runs" in a React web app that uses shadcn/ui components. The latest workflow runs with their status, which update while a run is in progress.

It uses the better-supabase `workflows` block (Workflows). It calls the hook `useWorkflowRuns` from `better-supabase/blocks/workflows/react`.

Steps:

1. If the app doesn't have the block yet, add the SQL with `npx better-supabase add workflows` and apply the migration.
2. Add the shadcn components the recipe uses: `npx shadcn add badge empty skeleton table`.
3. The recipe needs no glue: the hook calls the block from the client.
4. Write the component. Call `useWorkflowRuns` from `better-supabase/blocks/workflows/react`, starting from the recipe's snippet (`apps/examples/nextjs/src/features/workflows/components/workflow-runs.tsx`). Adapt it to the app's existing components, styling and data loading instead of copying it as is.
5. Check the result against the recipe and the block's docs: it typechecks, it calls the same hook, and it handles the loading and empty states the snippet handles.

Read the full code first:

- Recipe: https://bettersupabase.com/recipes/workflow-runs.md
- Block docs: https://bettersupabase.com/docs/blocks/workflows
```
