diff --git a/messages/en-US.json b/messages/en-US.json index 0193cded..064aee7a 100644 --- a/messages/en-US.json +++ b/messages/en-US.json @@ -1154,6 +1154,9 @@ "sidebarBluePrints": "Blueprints", "blueprints": "Blueprints", "blueprintsDescription": "Blueprints are declarative YAML configurations that define your resources and their settings", + "blueprintAdd": "Add Blueprint", + "searchBlueprintProgress": "Search blueprints...", + "source": "Source", "enableDockerSocket": "Enable Docker Blueprint", "enableDockerSocketDescription": "Enable Docker Socket label scraping for blueprint labels. Socket path must be provided to Newt.", "enableDockerSocketLink": "Learn More", diff --git a/server/routers/blueprints/listBluePrints.ts b/server/routers/blueprints/listBluePrints.ts index 0aca58b0..e25f0563 100644 --- a/server/routers/blueprints/listBluePrints.ts +++ b/server/routers/blueprints/listBluePrints.ts @@ -39,7 +39,8 @@ async function queryBlueprints(orgId: string, limit: number, offset: number) { blueprintId: blueprints.blueprintId, name: blueprints.name, source: blueprints.source, - succeeded: blueprints.succeeded + succeeded: blueprints.succeeded, + orgId: blueprints.orgId }) .from(blueprints) .leftJoin(orgs, eq(blueprints.orgId, orgs.orgId)) @@ -48,8 +49,15 @@ async function queryBlueprints(orgId: string, limit: number, offset: number) { return res; } +type BlueprintData = Omit< + Awaited>[number], + "source" +> & { + source: "API" | "WEB" | "CLI"; +}; + export type ListBlueprintsResponse = { - blueprints: NonNullable>>; + blueprints: NonNullable; pagination: { total: number; limit: number; offset: number }; }; @@ -108,7 +116,7 @@ export async function listBlueprints( return response(res, { data: { - blueprints: blueprintsList, + blueprints: blueprintsList as BlueprintData[], pagination: { total: count, limit, diff --git a/src/app/[orgId]/settings/blueprints/page.tsx b/src/app/[orgId]/settings/blueprints/page.tsx index cd4c71c8..e53aae9e 100644 --- a/src/app/[orgId]/settings/blueprints/page.tsx +++ b/src/app/[orgId]/settings/blueprints/page.tsx @@ -24,13 +24,17 @@ export default async function BluePrintsPage(props: BluePrintsPageProps) { try { const res = await internal.get< AxiosResponse - >(`/org/${params.orgId}/domains`, await authCookieHeader()); + >(`/org/${params.orgId}/blueprints`, await authCookieHeader()); blueprints = res.data.data.blueprints + console.log({ + ...res.data.data + }) } catch (e) { console.error(e); } + let org = null; try { const getOrg = cache(async () => @@ -49,6 +53,8 @@ export default async function BluePrintsPage(props: BluePrintsPageProps) { } const t = await getTranslations(); + + return ( <> @@ -56,7 +62,7 @@ export default async function BluePrintsPage(props: BluePrintsPageProps) { title={t("blueprints")} description={t("blueprintsDescription")} /> - + ); diff --git a/src/components/BlueprintsTable.tsx b/src/components/BlueprintsTable.tsx index 10b9705b..c5509bbd 100644 --- a/src/components/BlueprintsTable.tsx +++ b/src/components/BlueprintsTable.tsx @@ -3,8 +3,8 @@ import { ColumnDef } from "@tanstack/react-table"; import { DomainsDataTable } from "@app/components/DomainsDataTable"; import { Button } from "@app/components/ui/button"; -import { ArrowUpDown } from "lucide-react"; -import { useState } from "react"; +import { ArrowRight, ArrowUpDown, MoreHorizontal } from "lucide-react"; +import { useState, useTransition } from "react"; import ConfirmDeleteDialog from "@app/components/ConfirmDeleteDialog"; import { formatAxiosError } from "@app/lib/api"; import { createApiClient } from "@app/lib/api"; @@ -15,18 +15,177 @@ import { useTranslations } from "next-intl"; 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 Link from "next/link"; +import { ListBlueprintsResponse } from "@server/routers/blueprints"; -export type BlueprintRow = { - blueprintId: number; - source: string; - succeeded: boolean; - name: string; -}; +export type BlueprintRow = ListBlueprintsResponse['blueprints'][number] type Props = { blueprints: BlueprintRow[]; + orgId: string; }; -export default function BlueprintsTable({ blueprints }: Props) { - return <> +export default function BlueprintsTable({ blueprints, orgId }: Props) { + + const t = useTranslations(); + + const [isRefreshing, startTransition] = useTransition() + const router = useRouter() + + + const columns: ColumnDef[] = [ + { + accessorKey: "name", + header: ({ column }) => { + return ( + + ); + } + }, + { + accessorKey: "source", + 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 -; + // } + // } + }, + // { + // 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")} + // + // + // + // + + // + // + // + //
+ // ); + // } + // } + ]; + + 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