From 5246d84599e1b9d3c457eb90eb5c93b589cda477 Mon Sep 17 00:00:00 2001 From: Pablo Lara Date: Thu, 10 Oct 2024 14:02:21 +0200 Subject: [PATCH] chore: retrieve values for all scans in getScans --- actions/scans/actions.ts | 48 +++++++++ actions/scans/index.ts | 1 + app/(prowler)/scans/page.tsx | 7 +- components/providers/index.ts | 4 - .../providers/table/column-providers.tsx | 5 +- components/scans/table/column-get-scans.tsx | 97 ++++++++----------- .../scans/table/column-provider-scans.tsx | 15 ++- .../entities}/date-with-time.tsx | 3 +- .../entities/entity-info-short.tsx} | 31 +++--- components/ui/entities/index.ts | 4 + .../entities}/scan-status.tsx | 0 .../entities/snippet-id.tsx} | 13 +-- components/ui/table/status-badge.tsx | 22 ++--- components/users/table/ColumnsUser.tsx | 12 +-- types/components.ts | 41 ++++++++ 15 files changed, 178 insertions(+), 125 deletions(-) create mode 100644 actions/scans/actions.ts create mode 100644 actions/scans/index.ts rename components/{providers => ui/entities}/date-with-time.tsx (86%) rename components/{providers/provider-info-short.tsx => ui/entities/entity-info-short.tsx} (65%) create mode 100644 components/ui/entities/index.ts rename components/{providers => ui/entities}/scan-status.tsx (100%) rename components/{providers/snippet-id-provider.tsx => ui/entities/snippet-id.tsx} (70%) diff --git a/actions/scans/actions.ts b/actions/scans/actions.ts new file mode 100644 index 0000000000..81669dba15 --- /dev/null +++ b/actions/scans/actions.ts @@ -0,0 +1,48 @@ +"use server"; + +import { revalidatePath } from "next/cache"; +import { redirect } from "next/navigation"; + +import { auth } from "@/auth.config"; +import { parseStringify } from "@/lib"; + +export const getScans = async ({ + page = 1, + query = "", + sort = "", + filters = {}, +}) => { + const session = await auth(); + + if (isNaN(Number(page)) || page < 1) redirect("/scans"); + + const keyServer = process.env.API_BASE_URL; + const url = new URL(`${keyServer}/scans`); + + if (page) url.searchParams.append("page[number]", page.toString()); + if (query) url.searchParams.append("filter[search]", query); + if (sort) url.searchParams.append("sort", sort); + + // Handle multiple filters + Object.entries(filters).forEach(([key, value]) => { + if (key !== "filter[search]") { + url.searchParams.append(key, String(value)); + } + }); + + try { + const scans = await fetch(url.toString(), { + headers: { + Accept: "application/vnd.api+json", + Authorization: `Bearer ${session?.accessToken}`, + }, + }); + const data = await scans.json(); + const parsedData = parseStringify(data); + revalidatePath("/scans"); + return parsedData; + } catch (error) { + console.error("Error fetching providers:", error); + return undefined; + } +}; diff --git a/actions/scans/index.ts b/actions/scans/index.ts new file mode 100644 index 0000000000..8ff5a89aff --- /dev/null +++ b/actions/scans/index.ts @@ -0,0 +1 @@ +export * from "./actions"; diff --git a/app/(prowler)/scans/page.tsx b/app/(prowler)/scans/page.tsx index 56043a18fe..bf2c594d8a 100644 --- a/app/(prowler)/scans/page.tsx +++ b/app/(prowler)/scans/page.tsx @@ -2,6 +2,7 @@ import { Spacer } from "@nextui-org/react"; import { Suspense } from "react"; import { getProviders } from "@/actions/providers"; +import { getScans } from "@/actions/scans"; import { FilterControls, filterScans } from "@/components/filters"; import { ColumnGetScans, @@ -86,13 +87,13 @@ const SSRDataTableScans = async ({ // Extract query from filters const query = (filters["filter[search]"] as string) || ""; - const providersData = await getProviders({ query, page, sort, filters }); + const scansData = await getScans({ query, page, sort, filters }); return ( ); diff --git a/components/providers/index.ts b/components/providers/index.ts index 0751b3587c..5093cbf0ac 100644 --- a/components/providers/index.ts +++ b/components/providers/index.ts @@ -1,9 +1,5 @@ export * from "./add-provider"; export * from "./CheckConnectionProvider"; -export * from "./date-with-time"; export * from "./forms/delete-form"; export * from "./provider-info"; -export * from "./provider-info-short"; export * from "./radio-group-provider"; -export * from "./scan-status"; -export * from "./snippet-id-provider"; diff --git a/components/providers/table/column-providers.tsx b/components/providers/table/column-providers.tsx index 4ba3e7d0ff..bc6e8cf69b 100644 --- a/components/providers/table/column-providers.tsx +++ b/components/providers/table/column-providers.tsx @@ -3,12 +3,11 @@ import { ColumnDef } from "@tanstack/react-table"; import { add } from "date-fns"; +import { DateWithTime, SnippetId } from "@/components/ui/entities"; import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table"; import { ProviderProps } from "@/types"; -import { DateWithTime } from "../date-with-time"; import { ProviderInfo } from "../provider-info"; -import { SnippetIdProvider } from "../snippet-id-provider"; import { DataTableRowActions } from "./data-table-row-actions"; const getProviderData = (row: { original: ProviderProps }) => { @@ -47,7 +46,7 @@ export const ColumnProviders: ColumnDef[] = [ const { attributes: { uid }, } = getProviderData(row); - return ; + return ; }, }, { diff --git a/components/scans/table/column-get-scans.tsx b/components/scans/table/column-get-scans.tsx index caf45268e5..670d165c6f 100644 --- a/components/scans/table/column-get-scans.tsx +++ b/components/scans/table/column-get-scans.tsx @@ -3,61 +3,40 @@ import { ColumnDef } from "@tanstack/react-table"; import { add } from "date-fns"; -import { - DateWithTime, - ProviderInfo, - SnippetIdProvider, -} from "@/components/providers"; +import { DateWithTime, EntityInfoShort } from "@/components/ui/entities"; import { DataTableColumnHeader, StatusBadge } from "@/components/ui/table"; -import { ProviderProps } from "@/types"; +import { ScanProps } from "@/types"; import { DataTableRowActions } from "./data-table-row-actions"; -const getProviderData = (row: { original: ProviderProps }) => { +const getScanData = (row: { original: ScanProps }) => { return row.original; }; -export const ColumnGetScans: ColumnDef[] = [ +export const ColumnGetScans: ColumnDef[] = [ { - header: " ", - cell: ({ row }) =>

{row.index + 1}

, - }, - { - accessorKey: "account", + accessorKey: "name", header: ({ column }) => ( - + ), cell: ({ row }) => { const { - attributes: { connection, provider, alias }, - } = getProviderData(row); - return ( - - ); - }, - }, - { - accessorKey: "uid", - header: ({ column }) => ( - - ), - cell: ({ row }) => { - const { - attributes: { uid }, - } = getProviderData(row); - return ; + attributes: { name }, + } = getScanData(row); + return ; }, }, + { accessorKey: "status", - header: "Scan Status", - cell: () => { - // Temporarily overwriting the value until the API is functional. - return ; + header: ({ column }) => ( + + ), + cell: ({ row }) => { + const { + attributes: { state }, + } = getScanData(row); + return ; }, }, { @@ -65,15 +44,15 @@ export const ColumnGetScans: ColumnDef[] = [ header: ({ column }) => ( ), cell: ({ row }) => { const { - attributes: { updated_at }, - } = getProviderData(row); - return ; + attributes: { completed_at }, + } = getScanData(row); + return ; }, }, { @@ -81,36 +60,40 @@ export const ColumnGetScans: ColumnDef[] = [ header: "Next Scan", cell: ({ row }) => { const { - attributes: { updated_at }, - } = getProviderData(row); - const nextDay = add(new Date(updated_at), { + attributes: { scheduled_at, completed_at }, + } = getScanData(row); + const nextDay = add(new Date(completed_at), { hours: 24, }); - return ; + if (scheduled_at === null) + return ; + return ; }, }, { accessorKey: "resources", header: "Resources", - cell: () => { - // Temporarily overwriting the value until the API is functional. - return

{288}

; + cell: ({ row }) => { + const { + attributes: { unique_resource_count }, + } = getScanData(row); + return

{unique_resource_count}

; }, }, { - accessorKey: "added", + accessorKey: "started_at", header: ({ column }) => ( ), cell: ({ row }) => { const { - attributes: { inserted_at }, - } = getProviderData(row); - return ; + attributes: { started_at }, + } = getScanData(row); + return ; }, }, { diff --git a/components/scans/table/column-provider-scans.tsx b/components/scans/table/column-provider-scans.tsx index 9311f50086..c86fd0f434 100644 --- a/components/scans/table/column-provider-scans.tsx +++ b/components/scans/table/column-provider-scans.tsx @@ -3,8 +3,8 @@ import { ColumnDef } from "@tanstack/react-table"; import { AddIcon } from "@/components/icons/Icons"; -import { ProviderInfoShort } from "@/components/providers"; import { CustomButton } from "@/components/ui/custom"; +import { EntityInfoShort } from "@/components/ui/entities"; import { ProviderProps } from "@/types"; const getProviderData = (row: { original: ProviderProps }) => { @@ -20,11 +20,11 @@ export const ColumnProviderScans: ColumnDef[] = [ attributes: { connection, provider, alias, uid }, } = getProviderData(row); return ( - ); }, @@ -33,9 +33,6 @@ export const ColumnProviderScans: ColumnDef[] = [ accessorKey: "launchScan", header: "Launch Scan", cell: ({ row }) => { - const { - attributes: { uid }, - } = getProviderData(row); return ( [] = [ size="md" endContent={} onPress={() => { - console.log(uid); + console.log(row.original.id); }} > Start diff --git a/components/providers/date-with-time.tsx b/components/ui/entities/date-with-time.tsx similarity index 86% rename from components/providers/date-with-time.tsx rename to components/ui/entities/date-with-time.tsx index 1e968fae3f..ae89c61985 100644 --- a/components/providers/date-with-time.tsx +++ b/components/ui/entities/date-with-time.tsx @@ -2,7 +2,7 @@ import { format, parseISO } from "date-fns"; import React from "react"; interface DateWithTimeProps { - dateTime: string; // e.g., "2024-07-17T09:55:14.191475Z" + dateTime: string | null; // e.g., "2024-07-17T09:55:14.191475Z" showTime?: boolean; } @@ -10,6 +10,7 @@ export const DateWithTime: React.FC = ({ dateTime, showTime = true, }) => { + if (!dateTime) return --; const date = parseISO(dateTime); const formattedDate = format(date, "MMM dd, yyyy"); const formattedTime = format(date, "p 'UTC'"); diff --git a/components/providers/provider-info-short.tsx b/components/ui/entities/entity-info-short.tsx similarity index 65% rename from components/providers/provider-info-short.tsx rename to components/ui/entities/entity-info-short.tsx index dfd8d46ad8..3e71d7afbc 100644 --- a/components/providers/provider-info-short.tsx +++ b/components/ui/entities/entity-info-short.tsx @@ -5,23 +5,23 @@ import { AzureProviderBadge, GCPProviderBadge, KS8ProviderBadge, -} from "../icons/providers-badge"; -import { SnippetIdProvider } from "./snippet-id-provider"; +} from "../../icons/providers-badge"; +import { SnippetId } from "./snippet-id"; -interface ProviderInfoProps { - connected: boolean | null; - provider: "aws" | "azure" | "gcp" | "kubernetes"; - providerAlias: string; - providerId: string; +interface EntityInfoProps { + connected?: boolean | null; + cloudProvider?: "aws" | "azure" | "gcp" | "kubernetes"; + entityAlias?: string; + entityId?: string; } -export const ProviderInfoShort: React.FC = ({ - provider, - providerAlias, - providerId, +export const EntityInfoShort: React.FC = ({ + cloudProvider, + entityAlias, + entityId, }) => { const getProviderLogo = () => { - switch (provider) { + switch (cloudProvider) { case "aws": return ; case "azure": @@ -42,12 +42,9 @@ export const ProviderInfoShort: React.FC = ({
{getProviderLogo()}
- {providerAlias} + {entityAlias} - +
diff --git a/components/ui/entities/index.ts b/components/ui/entities/index.ts new file mode 100644 index 0000000000..70a72f858c --- /dev/null +++ b/components/ui/entities/index.ts @@ -0,0 +1,4 @@ +export * from "./date-with-time"; +export * from "./entity-info-short"; +export * from "./scan-status"; +export * from "./snippet-id"; diff --git a/components/providers/scan-status.tsx b/components/ui/entities/scan-status.tsx similarity index 100% rename from components/providers/scan-status.tsx rename to components/ui/entities/scan-status.tsx diff --git a/components/providers/snippet-id-provider.tsx b/components/ui/entities/snippet-id.tsx similarity index 70% rename from components/providers/snippet-id-provider.tsx rename to components/ui/entities/snippet-id.tsx index 0d3c76d566..54b3a4dfa9 100644 --- a/components/providers/snippet-id-provider.tsx +++ b/components/ui/entities/snippet-id.tsx @@ -1,16 +1,13 @@ import { Snippet } from "@nextui-org/react"; import React from "react"; -import { CopyIcon, DoneIcon, IdIcon } from "../icons"; +import { CopyIcon, DoneIcon, IdIcon } from "@/components/icons"; -interface SnippetIdProviderProps { - providerId: string; +interface SnippetIdProps { + entityId: string; [key: string]: any; } -export const SnippetIdProvider: React.FC = ({ - providerId, - ...props -}) => { +export const SnippetId: React.FC = ({ entityId, ...props }) => { return ( = ({

- {providerId} + {entityId}

diff --git a/components/ui/table/status-badge.tsx b/components/ui/table/status-badge.tsx index e688021cd4..ca8b3e2a49 100644 --- a/components/ui/table/status-badge.tsx +++ b/components/ui/table/status-badge.tsx @@ -2,27 +2,23 @@ import { Chip } from "@nextui-org/react"; import React from "react"; type Status = + | "available" + | "scheduled" + | "executing" | "completed" - | "pending" - | "cancelled" - | "fail" - | "success" - | "muted" - | "active" - | "inactive"; + | "failed" + | "cancelled"; const statusColorMap: Record< Status, "danger" | "warning" | "success" | "default" > = { + available: "default", + scheduled: "warning", + executing: "default", completed: "success", - pending: "warning", + failed: "danger", cancelled: "danger", - fail: "danger", - success: "success", - muted: "default", - active: "success", - inactive: "default", }; export const StatusBadge = ({ status }: { status: Status }) => { diff --git a/components/users/table/ColumnsUser.tsx b/components/users/table/ColumnsUser.tsx index 605120c707..20ac2dba9d 100644 --- a/components/users/table/ColumnsUser.tsx +++ b/components/users/table/ColumnsUser.tsx @@ -2,8 +2,7 @@ import { ColumnDef } from "@tanstack/react-table"; -import { DateWithTime } from "@/components/providers"; -import { StatusBadge } from "@/components/ui/table"; +import { DateWithTime } from "@/components/ui/entities"; import { UserActions } from "@/components/users"; import { UserProps } from "@/types"; @@ -44,14 +43,7 @@ export const ColumnsUser: ColumnDef[] = [ return ; }, }, - { - accessorKey: "status", - header: "Status", - cell: ({ row }) => { - const { status } = getUserData(row); - return ; - }, - }, + { accessorKey: "actions", header: () =>
Actions
, diff --git a/types/components.ts b/types/components.ts index 02018469dc..f88967e85e 100644 --- a/types/components.ts +++ b/types/components.ts @@ -66,6 +66,47 @@ export interface ProviderProps { }; } +export interface ScanProps { + type: "Scan"; + id: string; + attributes: { + name: string; + trigger: "scheduled" | "manual"; + state: + | "available" + | "scheduled" + | "executing" + | "completed" + | "failed" + | "cancelled"; + unique_resource_count: number; + progress: number; + scanner_args: { + only_logs?: boolean; + excluded_checks?: string[]; + aws_retries_max_attempts?: number; + } | null; + duration: number; + started_at: string; + completed_at: string; + scheduled_at: string; + }; + relationships: { + provider: { + data: { + id: string; + type: "Provider"; + }; + }; + task: { + data: { + id: string; + type: "Task"; + }; + }; + }; +} + export interface FindingProps { id: string; attributes: {