mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 21:11:53 +00:00
chore: retrieve values for all scans in getScans
This commit is contained in:
@@ -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;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1 @@
|
||||
export * from "./actions";
|
||||
@@ -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 (
|
||||
<DataTable
|
||||
columns={ColumnGetScans}
|
||||
data={providersData?.data || []}
|
||||
metadata={providersData?.meta}
|
||||
data={scansData?.data || []}
|
||||
metadata={scansData?.meta}
|
||||
customFilters={filterScans}
|
||||
/>
|
||||
);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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<ProviderProps>[] = [
|
||||
const {
|
||||
attributes: { uid },
|
||||
} = getProviderData(row);
|
||||
return <SnippetIdProvider providerId={uid} />;
|
||||
return <SnippetId className="h-6 max-w-44" entityId={uid} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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<ProviderProps>[] = [
|
||||
export const ColumnGetScans: ColumnDef<ScanProps>[] = [
|
||||
{
|
||||
header: " ",
|
||||
cell: ({ row }) => <p className="text-medium">{row.index + 1}</p>,
|
||||
},
|
||||
{
|
||||
accessorKey: "account",
|
||||
accessorKey: "name",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Account"} param="alias" />
|
||||
<DataTableColumnHeader column={column} title={"Name"} param="name" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { connection, provider, alias },
|
||||
} = getProviderData(row);
|
||||
return (
|
||||
<ProviderInfo
|
||||
connected={connection.connected}
|
||||
provider={provider}
|
||||
providerAlias={alias}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "uid",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Id"} param="uid" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { uid },
|
||||
} = getProviderData(row);
|
||||
return <SnippetIdProvider providerId={uid} />;
|
||||
attributes: { name },
|
||||
} = getScanData(row);
|
||||
return <EntityInfoShort entityAlias={name} entityId={row.original.id} />;
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Scan Status",
|
||||
cell: () => {
|
||||
// Temporarily overwriting the value until the API is functional.
|
||||
return <StatusBadge status={"completed"} />;
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader column={column} title={"Status"} param="state" />
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { state },
|
||||
} = getScanData(row);
|
||||
return <StatusBadge status={state} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -65,15 +44,15 @@ export const ColumnGetScans: ColumnDef<ProviderProps>[] = [
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Last Scan"}
|
||||
param="updated_at"
|
||||
title={"Completed At"}
|
||||
param="completed_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { updated_at },
|
||||
} = getProviderData(row);
|
||||
return <DateWithTime dateTime={updated_at} />;
|
||||
attributes: { completed_at },
|
||||
} = getScanData(row);
|
||||
return <DateWithTime dateTime={completed_at} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -81,36 +60,40 @@ export const ColumnGetScans: ColumnDef<ProviderProps>[] = [
|
||||
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 <DateWithTime dateTime={nextDay.toISOString()} />;
|
||||
if (scheduled_at === null)
|
||||
return <DateWithTime dateTime={nextDay.toISOString()} />;
|
||||
return <DateWithTime dateTime={scheduled_at} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "resources",
|
||||
header: "Resources",
|
||||
cell: () => {
|
||||
// Temporarily overwriting the value until the API is functional.
|
||||
return <p className="font-medium">{288}</p>;
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { unique_resource_count },
|
||||
} = getScanData(row);
|
||||
return <p className="font-medium">{unique_resource_count}</p>;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "added",
|
||||
accessorKey: "started_at",
|
||||
header: ({ column }) => (
|
||||
<DataTableColumnHeader
|
||||
column={column}
|
||||
title={"Added"}
|
||||
param="inserted_at"
|
||||
title={"Started At"}
|
||||
param="started_at"
|
||||
/>
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { inserted_at },
|
||||
} = getProviderData(row);
|
||||
return <DateWithTime dateTime={inserted_at} showTime={false} />;
|
||||
attributes: { started_at },
|
||||
} = getScanData(row);
|
||||
return <DateWithTime dateTime={started_at} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -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<ProviderProps>[] = [
|
||||
attributes: { connection, provider, alias, uid },
|
||||
} = getProviderData(row);
|
||||
return (
|
||||
<ProviderInfoShort
|
||||
<EntityInfoShort
|
||||
connected={connection.connected}
|
||||
provider={provider}
|
||||
providerAlias={alias}
|
||||
providerId={uid}
|
||||
cloudProvider={provider}
|
||||
entityAlias={alias}
|
||||
entityId={uid}
|
||||
/>
|
||||
);
|
||||
},
|
||||
@@ -33,9 +33,6 @@ export const ColumnProviderScans: ColumnDef<ProviderProps>[] = [
|
||||
accessorKey: "launchScan",
|
||||
header: "Launch Scan",
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { uid },
|
||||
} = getProviderData(row);
|
||||
return (
|
||||
<CustomButton
|
||||
className="w-full"
|
||||
@@ -45,7 +42,7 @@ export const ColumnProviderScans: ColumnDef<ProviderProps>[] = [
|
||||
size="md"
|
||||
endContent={<AddIcon size={20} />}
|
||||
onPress={() => {
|
||||
console.log(uid);
|
||||
console.log(row.original.id);
|
||||
}}
|
||||
>
|
||||
Start
|
||||
|
||||
@@ -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<DateWithTimeProps> = ({
|
||||
dateTime,
|
||||
showTime = true,
|
||||
}) => {
|
||||
if (!dateTime) return <span>--</span>;
|
||||
const date = parseISO(dateTime);
|
||||
const formattedDate = format(date, "MMM dd, yyyy");
|
||||
const formattedTime = format(date, "p 'UTC'");
|
||||
+14
-17
@@ -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<ProviderInfoProps> = ({
|
||||
provider,
|
||||
providerAlias,
|
||||
providerId,
|
||||
export const EntityInfoShort: React.FC<EntityInfoProps> = ({
|
||||
cloudProvider,
|
||||
entityAlias,
|
||||
entityId,
|
||||
}) => {
|
||||
const getProviderLogo = () => {
|
||||
switch (provider) {
|
||||
switch (cloudProvider) {
|
||||
case "aws":
|
||||
return <AWSProviderBadge width={35} height={35} />;
|
||||
case "azure":
|
||||
@@ -42,12 +42,9 @@ export const ProviderInfoShort: React.FC<ProviderInfoProps> = ({
|
||||
<div className="flex-shrink-0">{getProviderLogo()}</div>
|
||||
<div className="flex flex-col">
|
||||
<span className="text-md max-w-24 overflow-hidden text-ellipsis font-semibold lg:max-w-36">
|
||||
{providerAlias}
|
||||
{entityAlias}
|
||||
</span>
|
||||
<SnippetIdProvider
|
||||
className="h-5 max-w-44"
|
||||
providerId={providerId}
|
||||
/>
|
||||
<SnippetId className="h-5 max-w-44" entityId={entityId ?? ""} />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,4 @@
|
||||
export * from "./date-with-time";
|
||||
export * from "./entity-info-short";
|
||||
export * from "./scan-status";
|
||||
export * from "./snippet-id";
|
||||
+5
-8
@@ -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<SnippetIdProviderProps> = ({
|
||||
providerId,
|
||||
...props
|
||||
}) => {
|
||||
export const SnippetId: React.FC<SnippetIdProps> = ({ entityId, ...props }) => {
|
||||
return (
|
||||
<Snippet
|
||||
className="flex items-center py-0"
|
||||
@@ -26,7 +23,7 @@ export const SnippetIdProvider: React.FC<SnippetIdProviderProps> = ({
|
||||
<p className="flex items-center space-x-2">
|
||||
<IdIcon size={16} />
|
||||
<span className="no-scrollbar max-w-16 overflow-x-scroll text-sm">
|
||||
{providerId}
|
||||
{entityId}
|
||||
</span>
|
||||
</p>
|
||||
</Snippet>
|
||||
@@ -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 }) => {
|
||||
|
||||
@@ -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<UserProps>[] = [
|
||||
return <DateWithTime dateTime={dateAdded} showTime={false} />;
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "status",
|
||||
header: "Status",
|
||||
cell: ({ row }) => {
|
||||
const { status } = getUserData(row);
|
||||
return <StatusBadge status={status} />;
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
accessorKey: "actions",
|
||||
header: () => <div className="text-right">Actions</div>,
|
||||
|
||||
@@ -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: {
|
||||
|
||||
Reference in New Issue
Block a user