From dd052fa1afd4ca293eceecf9191c1f2bdd0c794f Mon Sep 17 00:00:00 2001 From: Fred KISSIE Date: Sat, 25 Oct 2025 03:06:45 +0200 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=84=20Gave=20a=20relooking=20to=20the?= =?UTF-8?q?=20blueprint=20table?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- messages/en-US.json | 1 + server/routers/blueprints/listBluePrints.ts | 21 +- server/routers/blueprints/types.ts | 8 + src/app/[orgId]/settings/blueprints/page.tsx | 2 +- src/components/BlueprintsTable.tsx | 279 ++++++++++--------- src/components/CreateBlueprintForm.tsx | 67 +---- 6 files changed, 180 insertions(+), 198 deletions(-) create mode 100644 server/routers/blueprints/types.ts diff --git a/messages/en-US.json b/messages/en-US.json index 6b0c01cb..e2b7b60f 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1164,6 +1164,7 @@ "blueprintErrorCreateDescription": "An error occurred when applying the blueprint", "blueprintErrorCreate": "Error creating blueprint", "searchBlueprintProgress": "Search blueprints...", + "appliedAt": "Applied at", "source": "Source", "contents": "Contents", "enableDockerSocket": "Enable Docker Blueprint", diff --git a/server/routers/blueprints/listBluePrints.ts b/server/routers/blueprints/listBluePrints.ts index c021e1e6..7e248a75 100644 --- a/server/routers/blueprints/listBluePrints.ts +++ b/server/routers/blueprints/listBluePrints.ts @@ -9,6 +9,7 @@ import logger from "@server/logger"; import { fromZodError } from "zod-validation-error"; import { OpenAPITags, registry } from "@server/openApi"; import { warn } from "console"; +import { BlueprintData } from "./types"; const listBluePrintsParamsSchema = z .object({ @@ -50,16 +51,18 @@ async function queryBlueprints(orgId: string, limit: number, offset: number) { return res; } -type BlueprintData = Omit< - Awaited>[number], - "source" | "createdAt" -> & { - source: "API" | "UI" | "NEWT"; - createdAt: Date; -}; - export type ListBlueprintsResponse = { - blueprints: NonNullable; + blueprints: NonNullable< + Pick< + BlueprintData, + | "blueprintId" + | "name" + | "source" + | "succeeded" + | "orgId" + | "createdAt" + >[] + >; pagination: { total: number; limit: number; offset: number }; }; diff --git a/server/routers/blueprints/types.ts b/server/routers/blueprints/types.ts new file mode 100644 index 00000000..a47cbc74 --- /dev/null +++ b/server/routers/blueprints/types.ts @@ -0,0 +1,8 @@ +import type { Blueprint } from "@server/db"; + +export type BlueprintSource = "API" | "UI" | "NEWT"; + +export type BlueprintData = Omit & { + source: BlueprintSource; + createdAt: Date; +}; diff --git a/src/app/[orgId]/settings/blueprints/page.tsx b/src/app/[orgId]/settings/blueprints/page.tsx index 21c13c35..58d5e8ed 100644 --- a/src/app/[orgId]/settings/blueprints/page.tsx +++ b/src/app/[orgId]/settings/blueprints/page.tsx @@ -19,7 +19,7 @@ type BluePrintsPageProps = { }; export const metadata: Metadata = { - title: "Blueprint" + title: "Blueprints" }; export default async function BluePrintsPage(props: BluePrintsPageProps) { diff --git a/src/components/BlueprintsTable.tsx b/src/components/BlueprintsTable.tsx index c5509bbd..f33bcdd0 100644 --- a/src/components/BlueprintsTable.tsx +++ b/src/components/BlueprintsTable.tsx @@ -3,7 +3,15 @@ import { ColumnDef } from "@tanstack/react-table"; import { DomainsDataTable } from "@app/components/DomainsDataTable"; import { Button } from "@app/components/ui/button"; -import { ArrowRight, ArrowUpDown, MoreHorizontal } from "lucide-react"; +import { + ArrowRight, + ArrowUpDown, + Globe, + LucideIcon, + MoreHorizontal, + Terminal, + Webhook +} from "lucide-react"; import { useState, useTransition } from "react"; import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { formatAxiosError } from "@app/lib/api"; @@ -16,11 +24,16 @@ import CreateDomainForm from "@app/components/CreateDomainForm"; import { useToast } from "@app/hooks/useToast"; import { useOrgContext } from "@app/hooks/useOrgContext"; import { DataTable } from "./ui/data-table"; -import { DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger } from "./ui/dropdown-menu"; +import { + DropdownMenu, + DropdownMenuContent, + DropdownMenuItem, + DropdownMenuTrigger +} from "./ui/dropdown-menu"; import Link from "next/link"; import { ListBlueprintsResponse } from "@server/routers/blueprints"; -export type BlueprintRow = ListBlueprintsResponse['blueprints'][number] +export type BlueprintRow = ListBlueprintsResponse["blueprints"][number]; type Props = { blueprints: BlueprintRow[]; @@ -28,14 +41,38 @@ type Props = { }; export default function BlueprintsTable({ blueprints, orgId }: Props) { - const t = useTranslations(); - const [isRefreshing, startTransition] = useTransition() - const router = useRouter() - + const [isRefreshing, startTransition] = useTransition(); + const router = useRouter(); const columns: ColumnDef[] = [ + { + accessorKey: "createdAt", + header: ({ column }) => { + return ( + + ); + }, + cell: ({ row }) => { + return ( + + ); + } + }, { accessorKey: "name", header: ({ column }) => { @@ -47,11 +84,12 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) { } > {t("name")} - + ); } }, + { accessorKey: "source", header: ({ column }) => { @@ -63,129 +101,118 @@ export default function BlueprintsTable({ blueprints, orgId }: Props) { } > {t("source")} + + + ); + }, + cell: ({ row }) => { + const originalRow = row.original; + switch (originalRow.source) { + case "API": { + return ( + + + API + + + + ); + } + case "NEWT": { + return ( + + + Newt CLI + + + + ); + } + case "UI": { + return ( + + + Dashboard{" "} + + + + ); + } + } + } + }, + { + accessorKey: "succeeded", + header: ({ column }) => { + return ( + ); }, - // cell: ({ row }) => { - // const originalRow = row.original; - // if ( - // originalRow.type == "newt" || - // originalRow.type == "wireguard" - // ) { - // if (originalRow.online) { - // return ( - // - //
- // {t("online")} - //
- // ); - // } else { - // return ( - // - //
- // {t("offline")} - //
- // ); - // } - // } else { - // return -; - // } - // } + cell: ({ row }) => { + const { succeeded } = row.original; + if (succeeded) { + return {t("success")}; + } else { + return ( + + {t("failed", { fallback: "Failed" })} + + ); + } + } }, - // { - // accessorKey: "nice", - // header: ({ column }) => { - // return ( - // - // ); - // }, - // // cell: ({ row }) => { - // // return ( - // //
- // // {row.original.nice} - // //
- // // ); - // // } - // }, - // { - // id: "actions", - // cell: ({ row }) => { - // const siteRow = row.original; - // return ( - //
- // - // - // - // - // - // - // - // {t("viewSettings")} - // - // - // { - // // setSelectedSite(siteRow); - // // setIsDeleteModalOpen(true); - // }} - // > - // - // {t("delete")} - // - // - // - // + { + id: "actions", + header: ({ column }) => { + return ( + + {t("actions")} + + ); + }, + cell: ({ row }) => { + const domain = row.original; - // - // - // - //
- // ); - // } - // } + return ( + + ); + } + } ]; - return { - router.push(`/${orgId}/settings/blueprints/create`); - }} - addButtonText={t('blueprintAdd')} - onRefresh={() => { - startTransition(() => router.refresh()) - }} - isRefreshing={isRefreshing} - defaultSort={{ - id: "name", - desc: false - }} - /> -} \ No newline at end of file + return ( + { + router.push(`/${orgId}/settings/blueprints/create`); + }} + addButtonText={t("blueprintAdd")} + onRefresh={() => { + startTransition(() => router.refresh()); + }} + isRefreshing={isRefreshing} + defaultSort={{ + id: "name", + desc: false + }} + /> + ); +} diff --git a/src/components/CreateBlueprintForm.tsx b/src/components/CreateBlueprintForm.tsx index 376b8424..57fce664 100644 --- a/src/components/CreateBlueprintForm.tsx +++ b/src/components/CreateBlueprintForm.tsx @@ -33,6 +33,7 @@ import { createApiClient, formatAxiosError } from "@app/lib/api"; import { AxiosResponse } from "axios"; import type { CreateBlueprintResponse } from "@server/routers/blueprints"; import { toast } from "@app/hooks/useToast"; +import { useRouter } from "next/navigation"; export type CreateBlueprintFormProps = { orgId: string; @@ -45,6 +46,7 @@ export default function CreateBlueprintForm({ const { env } = useEnvContext(); const api = createApiClient({ env }); const [, formAction, isSubmitting] = useActionState(onSubmit, null); + const router = useRouter(); const form = useForm({ resolver: zodResolver( @@ -87,7 +89,6 @@ export default function CreateBlueprintForm({ console.log({ isValid, payload - // json: parse(data.contents) }); const res = await api .put< @@ -107,68 +108,10 @@ export default function CreateBlueprintForm({ if (res && res.status === 201) { toast({ variant: "default", - title: "Success" + title: "Done", + description: res.data.data.message }); - // const id = res.data.data.resourceId; - // const niceId = res.data.data.niceId; - // setNiceId(niceId); - // // Create targets if any exist - // if (targets.length > 0) { - // try { - // for (const target of targets) { - // const data: any = { - // ip: target.ip, - // port: target.port, - // method: target.method, - // enabled: target.enabled, - // siteId: target.siteId, - // hcEnabled: target.hcEnabled, - // hcPath: target.hcPath || null, - // hcMethod: target.hcMethod || null, - // hcInterval: target.hcInterval || null, - // hcTimeout: target.hcTimeout || null, - // hcHeaders: target.hcHeaders || null, - // hcScheme: target.hcScheme || null, - // hcHostname: target.hcHostname || null, - // hcPort: target.hcPort || null, - // hcFollowRedirects: target.hcFollowRedirects || null, - // hcStatus: target.hcStatus || null - // }; - // // Only include path-related fields for HTTP resources - // if (isHttp) { - // data.path = target.path; - // data.pathMatchType = target.pathMatchType; - // data.rewritePath = target.rewritePath; - // data.rewritePathType = target.rewritePathType; - // data.priority = target.priority; - // } - // await api.put(`/resource/${id}/target`, data); - // } - // } catch (targetError) { - // console.error("Error creating targets:", targetError); - // toast({ - // variant: "destructive", - // title: t("targetErrorCreate"), - // description: formatAxiosError( - // targetError, - // t("targetErrorCreateDescription") - // ) - // }); - // } - // } - // if (isHttp) { - // router.push(`/${orgId}/settings/resources/${niceId}`); - // } else { - // const tcpUdpData = tcpUdpForm.getValues(); - // // Only show config snippets if enableProxy is explicitly true - // // if (tcpUdpData.enableProxy === true) { - // setShowSnippets(true); - // router.refresh(); - // // } else { - // // // If enableProxy is false or undefined, go directly to resource page - // // router.push(`/${orgId}/settings/resources/${id}`); - // // } - // } + router.push(`/${orgId}/settings/blueprints`); } } return (