feat: update workflow page ux
This commit is contained in:
parent
ffb117d85d
commit
c7772ca91e
@ -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,
|
|
||||||
};
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
@ -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>
|
||||||
|
@ -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),
|
||||||
}));
|
}));
|
||||||
|
53
web/src/server/getAllUserWorkflow.tsx
Normal file
53
web/src/server/getAllUserWorkflow.tsx
Normal 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;
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user