feat: update workflow page ux

This commit is contained in:
BennyKok 2024-01-19 18:12:07 +08:00
parent ffb117d85d
commit c7772ca91e
4 changed files with 103 additions and 92 deletions

View File

@ -1,16 +1,17 @@
import { setInitialUserData } from "../../../lib/setInitialUserData"; import { setInitialUserData } from "../../../lib/setInitialUserData";
import { getAllUserWorkflow } from "../../../server/getAllUserWorkflow";
import { WorkflowList } from "@/components/WorkflowList"; import { WorkflowList } from "@/components/WorkflowList";
import { db } from "@/db/db"; import { db } from "@/db/db";
import { usersTable, workflowTable, workflowVersionTable } from "@/db/schema"; import { usersTable } from "@/db/schema";
import { auth } from "@clerk/nextjs"; import { auth } from "@clerk/nextjs";
import { and, desc, eq, isNull } from "drizzle-orm"; import { eq } from "drizzle-orm";
export default function Home() { export default function Home() {
return <WorkflowServer />; return <WorkflowServer />;
} }
async function WorkflowServer() { async function WorkflowServer() {
const { userId, orgId } = await auth(); const { userId } = await auth();
if (!userId) { if (!userId) {
return <div>No auth</div>; return <div>No auth</div>;
@ -24,35 +25,11 @@ async function WorkflowServer() {
await setInitialUserData(userId); await setInitialUserData(userId);
} }
const workflow = await db.query.workflowTable.findMany({ const workflow = await getAllUserWorkflow();
// extras: {
// count: sql<number>`(select count(*) from ${workflowVersionTable})`.as(
// "count",
// ),
// },
with: {
versions: {
limit: 1,
orderBy: desc(workflowVersionTable.version),
},
},
orderBy: desc(workflowTable.updated_at),
where:
orgId != undefined
? eq(workflowTable.org_id, orgId)
: and(eq(workflowTable.user_id, userId), isNull(workflowTable.org_id)),
});
return ( if (!workflow) {
<WorkflowList return <div>No workflow found</div>;
data={workflow.map((x) => { }
return {
id: x.id, return <WorkflowList data={workflow} />;
email: x.name,
amount: x.versions[0]?.version ?? 0,
date: x.updated_at,
};
})}
/>
);
} }

View File

@ -1,6 +1,7 @@
"use client"; "use client";
import { getRelativeTime } from "../lib/getRelativeTime"; import { getRelativeTime } from "../lib/getRelativeTime";
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button"; import { Button } from "@/components/ui/button";
import { Checkbox } from "@/components/ui/checkbox"; import { Checkbox } from "@/components/ui/checkbox";
import { import {
@ -21,6 +22,7 @@ import {
TableRow, TableRow,
} from "@/components/ui/table"; } from "@/components/ui/table";
import { deleteWorkflow } from "@/server/deleteWorkflow"; import { deleteWorkflow } from "@/server/deleteWorkflow";
import type { getAllUserWorkflow } from "@/server/getAllUserWorkflow";
import type { import type {
ColumnDef, ColumnDef,
ColumnFiltersState, ColumnFiltersState,
@ -38,14 +40,11 @@ import {
import { ArrowUpDown, MoreHorizontal } from "lucide-react"; import { ArrowUpDown, MoreHorizontal } from "lucide-react";
import * as React from "react"; import * as React from "react";
export type Payment = { export type WorkflowItemList = NonNullable<
id: string; Awaited<ReturnType<typeof getAllUserWorkflow>>
amount: number; >[0];
date: Date;
email: string;
};
export const columns: ColumnDef<Payment>[] = [ export const columns: ColumnDef<WorkflowItemList>[] = [
{ {
accessorKey: "id", accessorKey: "id",
id: "select", id: "select",
@ -70,7 +69,7 @@ export const columns: ColumnDef<Payment>[] = [
enableHiding: false, enableHiding: false,
}, },
{ {
accessorKey: "email", accessorKey: "name",
header: ({ column }) => { header: ({ column }) => {
return ( return (
<button <button
@ -83,27 +82,35 @@ export const columns: ColumnDef<Payment>[] = [
); );
}, },
cell: ({ row }) => { cell: ({ row }) => {
const workflow = row.original;
return ( return (
<a className="hover:underline" href={`/workflows/${row.original.id}`}> <a
{row.getValue("email")} className="hover:underline flex gap-2"
href={`/workflows/${workflow.id}`}
>
<span className="truncate max-w-[200px]">{row.original.name}</span>
<Badge variant="default">v{row.original.versions[0]?.version}</Badge>
{workflow.deployments?.[0] && <Badge variant="success">Public</Badge>}
</a> </a>
); );
}, },
}, },
{ {
accessorKey: "amount", accessorKey: "creator",
header: () => <div className="text-left">Version</div>, header: ({ column }) => {
return (
<button
className="flex items-center hover:underline"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
>
Creator
<ArrowUpDown className="ml-2 h-4 w-4" />
</button>
);
},
cell: ({ row }) => { cell: ({ row }) => {
const amount = parseFloat(row.getValue("amount")); return <Badge variant="cyan">{row.original.user.name}</Badge>;
// Format the amount as a dollar amount
// const formatted = new Intl.NumberFormat("en-US", {
// style: "currency",
// currency: "USD",
// }).format(amount);
return <div className="text-left font-medium">{amount}</div>;
}, },
}, },
{ {
@ -113,7 +120,7 @@ export const columns: ColumnDef<Payment>[] = [
header: ({ column }) => { header: ({ column }) => {
return ( return (
<button <button
className="w-full flex items-center justify-end hover:underline" className="w-full flex items-center justify-end hover:underline truncate"
// variant="ghost" // variant="ghost"
onClick={() => column.toggleSorting(column.getIsSorted() === "asc")} onClick={() => column.toggleSorting(column.getIsSorted() === "asc")}
> >
@ -123,8 +130,8 @@ export const columns: ColumnDef<Payment>[] = [
); );
}, },
cell: ({ row }) => ( cell: ({ row }) => (
<div className="w-full capitalize text-right"> <div className="w-full capitalize text-right truncate">
{getRelativeTime(row.original.date)} {getRelativeTime(row.original.updated_at)}
</div> </div>
), ),
}, },
@ -148,14 +155,10 @@ export const columns: ColumnDef<Payment>[] = [
className="text-destructive" className="text-destructive"
onClick={() => { onClick={() => {
deleteWorkflow(workflow.id); deleteWorkflow(workflow.id);
// navigator.clipboard.writeText(payment.id)
}} }}
> >
Delete Workflow Delete Workflow
</DropdownMenuItem> </DropdownMenuItem>
{/* <DropdownMenuSeparator />
<DropdownMenuItem>View customer</DropdownMenuItem>
<DropdownMenuItem>View payment details</DropdownMenuItem> */}
</DropdownMenuContent> </DropdownMenuContent>
</DropdownMenu> </DropdownMenu>
); );
@ -163,7 +166,7 @@ export const columns: ColumnDef<Payment>[] = [
}, },
]; ];
export function WorkflowList({ data }: { data: Payment[] }) { export function WorkflowList({ data }: { data: WorkflowItemList[] }) {
const [sorting, setSorting] = React.useState<SortingState>([]); const [sorting, setSorting] = React.useState<SortingState>([]);
const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>( const [columnFilters, setColumnFilters] = React.useState<ColumnFiltersState>(
[] []
@ -196,38 +199,12 @@ export function WorkflowList({ data }: { data: Payment[] }) {
<div className="flex flex-row w-full items-center py-4"> <div className="flex flex-row w-full items-center py-4">
<Input <Input
placeholder="Filter workflows..." placeholder="Filter workflows..."
value={(table.getColumn("email")?.getFilterValue() as string) ?? ""} value={(table.getColumn("name")?.getFilterValue() as string) ?? ""}
onChange={(event) => onChange={(event) =>
table.getColumn("email")?.setFilterValue(event.target.value) table.getColumn("name")?.setFilterValue(event.target.value)
} }
className="max-w-sm" className="max-w-sm"
/> />
{/* <DropdownMenu>
<DropdownMenuTrigger asChild>
<Button variant="outline" className="ml-auto">
Columns <ChevronDown className="ml-2 h-4 w-4" />
</Button>
</DropdownMenuTrigger>
<DropdownMenuContent align="end">
{table
.getAllColumns()
.filter((column) => column.getCanHide())
.map((column) => {
return (
<DropdownMenuCheckboxItem
key={column.id}
className="capitalize"
checked={column.getIsVisible()}
onCheckedChange={(value) =>
column.toggleVisibility(!!value)
}
>
{column.id}
</DropdownMenuCheckboxItem>
);
})}
</DropdownMenuContent>
</DropdownMenu> */}
</div> </div>
<ScrollArea className="h-full w-full rounded-md border"> <ScrollArea className="h-full w-full rounded-md border">
<Table> <Table>

View File

@ -35,7 +35,11 @@ export const workflowTable = dbSchema.table("workflows", {
updated_at: timestamp("updated_at").defaultNow().notNull(), updated_at: timestamp("updated_at").defaultNow().notNull(),
}); });
export const workflowRelations = relations(workflowTable, ({ many }) => ({ export const workflowRelations = relations(workflowTable, ({ many, one }) => ({
user: one(usersTable, {
fields: [workflowTable.user_id],
references: [usersTable.id],
}),
versions: many(workflowVersionTable), versions: many(workflowVersionTable),
deployments: many(deploymentsTable), deployments: many(deploymentsTable),
})); }));

View File

@ -0,0 +1,53 @@
import { db } from "@/db/db";
import {
deploymentsTable,
workflowTable,
workflowVersionTable,
} from "@/db/schema";
import { auth } from "@clerk/nextjs";
import { and, desc, eq, isNull } from "drizzle-orm";
export async function getAllUserWorkflow() {
const { userId, orgId } = await auth();
if (!userId) {
return null;
}
const workflow = await db.query.workflowTable.findMany({
with: {
user: {
columns: {
name: true,
},
},
versions: {
limit: 1,
orderBy: desc(workflowVersionTable.version),
columns: {
id: true,
version: true,
},
},
deployments: {
limit: 1,
where: eq(deploymentsTable.environment, "public-share"),
columns: {
id: true,
},
},
},
columns: {
id: true,
updated_at: true,
name: true,
},
orderBy: desc(workflowTable.updated_at),
where:
orgId != undefined
? eq(workflowTable.org_id, orgId)
: and(eq(workflowTable.user_id, userId), isNull(workflowTable.org_id)),
});
return workflow;
}