chore: retrieve values for all scans in getScans

This commit is contained in:
Pablo Lara
2024-10-10 14:02:21 +02:00
parent 9409ea75e5
commit 5246d84599
15 changed files with 178 additions and 125 deletions
+48
View File
@@ -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;
}
};
+1
View File
@@ -0,0 +1 @@
export * from "./actions";
+4 -3
View File
@@ -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}
/>
);
-4
View File
@@ -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} />;
},
},
{
+40 -57
View File
@@ -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'");
@@ -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>
+4
View File
@@ -0,0 +1,4 @@
export * from "./date-with-time";
export * from "./entity-info-short";
export * from "./scan-status";
export * from "./snippet-id";
@@ -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>
+9 -13
View File
@@ -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 -10
View File
@@ -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>,
+41
View File
@@ -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: {