diff --git a/app/(prowler)/providers/page.tsx b/app/(prowler)/providers/page.tsx index d3cd8c1611..2301d26738 100644 --- a/app/(prowler)/providers/page.tsx +++ b/app/(prowler)/providers/page.tsx @@ -1,20 +1,11 @@ import { Spacer } from "@nextui-org/react"; import React from "react"; -import { CustomTable, Header, ModalWrap } from "@/components"; +import { ColumnsProviders, DataTable, Header, ModalWrap } from "@/components"; +import { getProvider } from "@/lib/actions"; -const visibleColumns: string[] = [ - "account", - "group", - "scan_status", - "last_scan", - "next_scan", - "resources", - "added", - "actions", -]; - -export default function Providers() { +export default async function Providers() { + const providers = await getProvider(); const onSave = async () => { "use server"; // event we want to pass down, ex. console.log("### hello"); @@ -24,23 +15,21 @@ export default function Providers() { <>
- - - -

Modal body content

- - } - actionButtonLabel="Save" - onAction={onSave} - openButtonLabel="Open Modal" - /> +
+ +

Modal body content

+ + } + actionButtonLabel="Save" + onAction={onSave} + openButtonLabel="Add Cloud Accounts" + /> + + +
); } diff --git a/components/index.ts b/components/index.ts index f4acf6e356..faa5b19c57 100644 --- a/components/index.ts +++ b/components/index.ts @@ -1,7 +1,7 @@ export * from "./providers/DateWithTime"; export * from "./providers/ProviderInfo"; export * from "./providers/ScanStatus"; -export * from "./providers/table/columns"; +export * from "./providers/table/ColumnsProviders"; export * from "./providers/table/DataTable"; export * from "./ui/header/Header"; export * from "./ui/modal"; diff --git a/components/providers/DateWithTime.tsx b/components/providers/DateWithTime.tsx index 9895483e31..1e968fae3f 100644 --- a/components/providers/DateWithTime.tsx +++ b/components/providers/DateWithTime.tsx @@ -16,7 +16,7 @@ export const DateWithTime: React.FC = ({ return (
-
+
{formattedDate} {showTime && ( {formattedTime} diff --git a/components/providers/table/ColumnsProviders.tsx b/components/providers/table/ColumnsProviders.tsx new file mode 100644 index 0000000000..c362d95f27 --- /dev/null +++ b/components/providers/table/ColumnsProviders.tsx @@ -0,0 +1,111 @@ +"use client"; + +import { + Button, + Dropdown, + DropdownItem, + DropdownMenu, + DropdownTrigger, +} from "@nextui-org/react"; +import { ColumnDef } from "@tanstack/react-table"; +import { add } from "date-fns"; + +import { VerticalDotsIcon } from "@/components/icons"; +import { StatusBadge } from "@/components/ui/table/StatusBadge"; +import { ProviderProps } from "@/types"; + +import { DateWithTime } from "../DateWithTime"; +import { ProviderInfo } from "../ProviderInfo"; + +export const ColumnsProviders: ColumnDef[] = [ + { + header: "ID", + cell: ({ row }) =>

{row.index + 1}

, + }, + { + accessorKey: "account", + header: "Account", + cell: ({ row }) => { + const provider = row.original; + return ( + + ); + }, + }, + { + accessorKey: "status", + header: "Scan Status", + cell: ({ row }) => { + const provider = row.original; + return ; + }, + }, + { + accessorKey: "lastScan", + header: "Last Scan", + cell: ({ row }) => { + const provider = row.original; + return ; + }, + }, + { + accessorKey: "nextScan", + header: "Next Scan", + cell: ({ row }) => { + const provider = row.original; + const nextDay = add(new Date(provider.attributes.updated_at), { + hours: 24, + }); + return ; + }, + }, + { + accessorKey: "resources", + header: "Resources", + cell: ({ row }) => { + const provider = row.original; + return

{provider.attributes.resources}

; + }, + }, + { + accessorKey: "added", + header: "Added", + cell: ({ row }) => { + const provider = row.original; + return ( + + ); + }, + }, + { + accessorKey: "actions", + header: () =>
Actions
, + id: "actions", + cell: () => { + // const provider = row.original; + return ( +
+ + + + + + Manage + Delete + + +
+ ); + }, + }, +]; diff --git a/components/providers/table/DataTable.tsx b/components/providers/table/DataTable.tsx new file mode 100644 index 0000000000..cfcf74ff2a --- /dev/null +++ b/components/providers/table/DataTable.tsx @@ -0,0 +1,109 @@ +"use client"; + +import { Button } from "@nextui-org/react"; +import { + ColumnDef, + flexRender, + getCoreRowModel, + getPaginationRowModel, + useReactTable, +} from "@tanstack/react-table"; + +import { + Table, + TableBody, + TableCell, + TableHead, + TableHeader, + TableRow, +} from "@/components/ui/table/Table"; + +interface DataTableProps { + columns: ColumnDef[]; + data: TData[]; +} + +export function DataTable({ + columns, + data, +}: DataTableProps) { + const table = useReactTable({ + data, + columns, + getCoreRowModel: getCoreRowModel(), + getPaginationRowModel: getPaginationRowModel(), + }); + + return ( + <> +
+ + + {table.getHeaderGroups().map((headerGroup) => ( + + {headerGroup.headers.map((header) => { + return ( + + {header.isPlaceholder + ? null + : flexRender( + header.column.columnDef.header, + header.getContext(), + )} + + ); + })} + + ))} + + + {table.getRowModel().rows?.length ? ( + table.getRowModel().rows.map((row) => ( + + {row.getVisibleCells().map((cell) => ( + + {flexRender( + cell.column.columnDef.cell, + cell.getContext(), + )} + + ))} + + )) + ) : ( + + + No results. + + + )} + +
+
+
+ + +
+ + ); +} diff --git a/components/ui/table/StatusBadge.tsx b/components/ui/table/StatusBadge.tsx new file mode 100644 index 0000000000..a1dea200aa --- /dev/null +++ b/components/ui/table/StatusBadge.tsx @@ -0,0 +1,25 @@ +import { Chip } from "@nextui-org/react"; +import React from "react"; + +type Status = "completed" | "pending" | "cancelled"; + +export const statusColorMap: Record = + { + completed: "success", + pending: "warning", + cancelled: "danger", + }; + +export const StatusBadge = ({ status }: { status: Status }) => { + return ( + + {status} + + ); +}; diff --git a/components/ui/table/Table.tsx b/components/ui/table/Table.tsx new file mode 100644 index 0000000000..cdc1f5cfe6 --- /dev/null +++ b/components/ui/table/Table.tsx @@ -0,0 +1,117 @@ +import * as React from "react"; + +import { cn } from "@/lib/utils"; + +const Table = React.forwardRef< + HTMLTableElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+ + +)); +Table.displayName = "Table"; + +const TableHeader = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableHeader.displayName = "TableHeader"; + +const TableBody = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableBody.displayName = "TableBody"; + +const TableFooter = React.forwardRef< + HTMLTableSectionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + tr]:last:border-b-0 dark:bg-slate-800/50", + className, + )} + {...props} + /> +)); +TableFooter.displayName = "TableFooter"; + +const TableRow = React.forwardRef< + HTMLTableRowElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableRow.displayName = "TableRow"; + +const TableHead = React.forwardRef< + HTMLTableCellElement, + React.ThHTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableHead.displayName = "TableHead"; + +const TableCell = React.forwardRef< + HTMLTableCellElement, + React.TdHTMLAttributes +>(({ className, ...props }, ref) => ( + +)); +TableCell.displayName = "TableCell"; + +const TableCaption = React.forwardRef< + HTMLTableCaptionElement, + React.HTMLAttributes +>(({ className, ...props }, ref) => ( +
+)); +TableCaption.displayName = "TableCaption"; + +export { + Table, + TableBody, + TableCaption, + TableCell, + TableFooter, + TableHead, + TableHeader, + TableRow, +}; diff --git a/lib/actions/provider.actions.ts b/lib/actions/provider.actions.ts index 02cb2578e9..12ee153dc1 100644 --- a/lib/actions/provider.actions.ts +++ b/lib/actions/provider.actions.ts @@ -3,8 +3,9 @@ import "server-only"; import { parseStringify } from "../utils"; export const getProvider = async () => { + const key = process.env.LOCAL_SITE_URL; try { - const providers = await fetch("http://localhost:3000/api/providers"); + const providers = await fetch(`${key}/api/providers`); const data = await providers.json(); return parseStringify(data); } catch (error) {