mirror of
https://github.com/prowler-cloud/prowler.git
synced 2026-07-24 21:11:53 +00:00
feat: resources in finding tables (#7813)
This commit is contained in:
+3
-3
@@ -7,6 +7,7 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
### 🚀 Added
|
||||
|
||||
- New profile page with details about the user and their roles. [(#7780)](https://github.com/prowler-cloud/prowler/pull/7780)
|
||||
- Improved `SnippetChip` component and show resource name in new findings table. [(#7813)](https://github.com/prowler-cloud/prowler/pull/7813)
|
||||
|
||||
---
|
||||
|
||||
@@ -22,14 +23,13 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
|
||||
## [v1.7.0] (Prowler v5.7.0)
|
||||
|
||||
|
||||
### 🚀 Added
|
||||
|
||||
- Add a new chart to show the split between passed and failed findings. [(#7680)](https://github.com/prowler-cloud/prowler/pull/7680)
|
||||
- Added `Accordion` component. [(#7700)](https://github.com/prowler-cloud/prowler/pull/7700)
|
||||
- Improve `Provider UID` filter by adding more context and enhancing the UI/UX. [(#7741)](https://github.com/prowler-cloud/prowler/pull/7741)
|
||||
- Added an AWS CloudFormation Quick Link to the IAM Role credentials step [(#7735)](https://github.com/prowler-cloud/prowler/pull/7735)
|
||||
– Use `getLatestFindings` on findings page when no scan or date filters are applied. [(#7756)](https://github.com/prowler-cloud/prowler/pull/7756)
|
||||
– Use `getLatestFindings` on findings page when no scan or date filters are applied. [(#7756)](https://github.com/prowler-cloud/prowler/pull/7756)
|
||||
|
||||
### 🐞 Fixes
|
||||
|
||||
@@ -102,7 +102,7 @@ All notable changes to the **Prowler UI** are documented in this file.
|
||||
- Revalidate the page when a role is deleted. [(#6976)](https://github.com/prowler-cloud/prowler/pull/6976)
|
||||
- Allows removing group visibility when creating a role. [(#7088)](https://github.com/prowler-cloud/prowler/pull/7088)
|
||||
- Displays correct error messages when deleting a user. [(#7089)](https://github.com/prowler-cloud/prowler/pull/7089)
|
||||
- Updated label: *"Select a scan job"* → *"Select a cloud provider"*. [(#7107)](https://github.com/prowler-cloud/prowler/pull/7107)
|
||||
- Updated label: _"Select a scan job"_ → _"Select a cloud provider"_. [(#7107)](https://github.com/prowler-cloud/prowler/pull/7107)
|
||||
- Display uid if alias is missing when creating a group. [(#7137)](https://github.com/prowler-cloud/prowler/pull/7137)
|
||||
|
||||
---
|
||||
|
||||
@@ -52,7 +52,6 @@ export default async function Findings({
|
||||
const uniqueServices = metadataInfoData?.data?.attributes?.services || [];
|
||||
const uniqueResourceTypes =
|
||||
metadataInfoData?.data?.attributes?.resource_types || [];
|
||||
// Get findings data
|
||||
|
||||
// Extract provider UIDs
|
||||
const providerUIDs: string[] = Array.from(
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Database } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { DataTableRowDetails } from "@/components/findings/table";
|
||||
import { InfoIcon } from "@/components/icons";
|
||||
import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
|
||||
import {
|
||||
DateWithTime,
|
||||
EntityInfoShort,
|
||||
SnippetChip,
|
||||
} from "@/components/ui/entities";
|
||||
import { TriggerSheet } from "@/components/ui/sheet";
|
||||
import {
|
||||
DataTableColumnHeader,
|
||||
@@ -63,7 +68,7 @@ const FindingDetailsCell = ({ row }: { row: any }) => {
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<div className="flex max-w-10 justify-center">
|
||||
<TriggerSheet
|
||||
triggerComponent={<InfoIcon className="text-primary" size={16} />}
|
||||
title="Finding Details"
|
||||
@@ -105,8 +110,10 @@ export const ColumnFindings: ColumnDef<FindingProps>[] = [
|
||||
return (
|
||||
<div className="relative flex max-w-[410px] flex-row items-center gap-2 3xl:max-w-[660px]">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{(delta === "new" || delta === "changed") && (
|
||||
{delta === "new" || delta === "changed" ? (
|
||||
<DeltaIndicator delta={delta} />
|
||||
) : (
|
||||
<div className="w-2" />
|
||||
)}
|
||||
<p className="mr-7 whitespace-normal break-words text-sm">
|
||||
{checktitle}
|
||||
@@ -119,6 +126,21 @@ export const ColumnFindings: ColumnDef<FindingProps>[] = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "resourceName",
|
||||
header: "Resource name",
|
||||
cell: ({ row }) => {
|
||||
const resourceName = getResourceData(row, "name");
|
||||
|
||||
return (
|
||||
<SnippetChip
|
||||
value={resourceName as string}
|
||||
formatter={(value: string) => `...${value.slice(-10)}`}
|
||||
icon={<Database size={16} />}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "severity",
|
||||
header: ({ column }) => (
|
||||
|
||||
@@ -1,18 +1,22 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { Database } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { Muted } from "@/components/findings/muted";
|
||||
import { DataTableRowDetails } from "@/components/findings/table";
|
||||
import { DeltaIndicator } from "@/components/findings/table/delta-indicator";
|
||||
import { InfoIcon } from "@/components/icons";
|
||||
import { DateWithTime, EntityInfoShort } from "@/components/ui/entities";
|
||||
import {
|
||||
DateWithTime,
|
||||
EntityInfoShort,
|
||||
SnippetChip,
|
||||
} from "@/components/ui/entities";
|
||||
import { TriggerSheet } from "@/components/ui/sheet";
|
||||
import { SeverityBadge, StatusFindingBadge } from "@/components/ui/table";
|
||||
import { FindingProps, ProviderType } from "@/types";
|
||||
|
||||
import { Muted } from "../../../findings/muted";
|
||||
|
||||
const getFindingsData = (row: { original: FindingProps }) => {
|
||||
return row.original;
|
||||
};
|
||||
@@ -81,8 +85,10 @@ export const ColumnNewFindingsToDate: ColumnDef<FindingProps>[] = [
|
||||
return (
|
||||
<div className="relative flex max-w-[410px] flex-row items-center gap-2 3xl:max-w-[660px]">
|
||||
<div className="flex flex-row items-center gap-4">
|
||||
{(delta === "new" || delta === "changed") && (
|
||||
{delta === "new" || delta === "changed" ? (
|
||||
<DeltaIndicator delta={delta} />
|
||||
) : (
|
||||
<div className="w-2" />
|
||||
)}
|
||||
<p className="mr-7 whitespace-normal break-words text-sm">
|
||||
{checktitle}
|
||||
@@ -95,6 +101,21 @@ export const ColumnNewFindingsToDate: ColumnDef<FindingProps>[] = [
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "resourceName",
|
||||
header: "Resource name",
|
||||
cell: ({ row }) => {
|
||||
const resourceName = getResourceData(row, "name");
|
||||
|
||||
return (
|
||||
<SnippetChip
|
||||
value={resourceName as string}
|
||||
formatter={(value) => `...${value.slice(-10)}`}
|
||||
icon={<Database size={16} />}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
{
|
||||
accessorKey: "severity",
|
||||
header: "Severity",
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import { Chip } from "@nextui-org/react";
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
|
||||
import { DateWithTime, SnippetId } from "@/components/ui/entities";
|
||||
import { DateWithTime, SnippetChip } from "@/components/ui/entities";
|
||||
import { DataTableColumnHeader } from "@/components/ui/table";
|
||||
import { ProviderProps } from "@/types";
|
||||
|
||||
@@ -74,7 +74,7 @@ export const ColumnProviders: ColumnDef<ProviderProps>[] = [
|
||||
const {
|
||||
attributes: { uid },
|
||||
} = getProviderData(row);
|
||||
return <SnippetId className="h-7" entityId={uid} />;
|
||||
return <SnippetChip value={uid} className="h-7" />;
|
||||
},
|
||||
},
|
||||
{
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import React from "react";
|
||||
|
||||
import { IdIcon } from "@/components/icons";
|
||||
import { ProviderType } from "@/types";
|
||||
|
||||
import { getProviderLogo } from "./get-provider-logo";
|
||||
import { SnippetId } from "./snippet-id";
|
||||
import { SnippetChip } from "./snippet-chip";
|
||||
|
||||
interface EntityInfoProps {
|
||||
cloudProvider: ProviderType;
|
||||
@@ -26,9 +27,10 @@ export const EntityInfoShort: React.FC<EntityInfoProps> = ({
|
||||
{entityAlias && (
|
||||
<span className="text-xs text-default-500">{entityAlias}</span>
|
||||
)}
|
||||
<SnippetId
|
||||
entityId={entityId ?? ""}
|
||||
<SnippetChip
|
||||
value={entityId ?? ""}
|
||||
hideCopyButton={hideCopyButton}
|
||||
icon={<IdIcon size={16} />}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3,5 +3,4 @@ export * from "./entity-info-short";
|
||||
export * from "./get-provider-logo";
|
||||
export * from "./info-field";
|
||||
export * from "./scan-status";
|
||||
export * from "./snippet-id";
|
||||
export * from "./snippet-label";
|
||||
export * from "./snippet-chip";
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import { cn, Snippet, Tooltip } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { CopyIcon, DoneIcon } from "@/components/icons";
|
||||
|
||||
interface SnippetChipProps {
|
||||
value: string;
|
||||
ariaLabel?: string;
|
||||
icon?: React.ReactNode;
|
||||
hideCopyButton?: boolean;
|
||||
formatter?: (value: string) => string;
|
||||
className?: string;
|
||||
}
|
||||
export const SnippetChip = ({
|
||||
value,
|
||||
hideCopyButton = false,
|
||||
ariaLabel = `Copy ${value} to clipboard`,
|
||||
icon,
|
||||
formatter,
|
||||
className,
|
||||
...props
|
||||
}: SnippetChipProps) => {
|
||||
return (
|
||||
<Snippet
|
||||
className={cn("h-6", className)}
|
||||
color="default"
|
||||
size="sm"
|
||||
variant="flat"
|
||||
radius="lg"
|
||||
hideSymbol
|
||||
copyIcon={<CopyIcon size={16} />}
|
||||
checkIcon={<DoneIcon size={16} />}
|
||||
hideCopyButton={hideCopyButton}
|
||||
codeString={value}
|
||||
{...props}
|
||||
>
|
||||
<div className="flex items-center space-x-2" aria-label={ariaLabel}>
|
||||
{icon}
|
||||
<Tooltip content={value} placement="top" size="sm">
|
||||
<span className="no-scrollbar max-w-24 overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-xs">
|
||||
{formatter ? formatter(value) : value}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</div>
|
||||
</Snippet>
|
||||
);
|
||||
};
|
||||
@@ -1,39 +0,0 @@
|
||||
import { Snippet, Tooltip } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { CopyIcon, DoneIcon, IdIcon } from "@/components/icons";
|
||||
|
||||
interface SnippetIdProps {
|
||||
entityId: string;
|
||||
hideCopyButton?: boolean;
|
||||
[key: string]: any;
|
||||
}
|
||||
export const SnippetId: React.FC<SnippetIdProps> = ({
|
||||
entityId,
|
||||
hideCopyButton = false,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
<Snippet
|
||||
className="flex h-6 items-center py-0"
|
||||
color="default"
|
||||
size="sm"
|
||||
variant="flat"
|
||||
radius="lg"
|
||||
hideSymbol
|
||||
copyIcon={<CopyIcon size={16} />}
|
||||
checkIcon={<DoneIcon size={16} />}
|
||||
hideCopyButton={hideCopyButton}
|
||||
{...props}
|
||||
>
|
||||
<p className="flex items-center space-x-2">
|
||||
<IdIcon size={18} />
|
||||
<Tooltip content={entityId} placement="top">
|
||||
<span className="no-scrollbar w-24 overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-xs">
|
||||
{entityId}
|
||||
</span>
|
||||
</Tooltip>
|
||||
</p>
|
||||
</Snippet>
|
||||
);
|
||||
};
|
||||
@@ -1,32 +0,0 @@
|
||||
import { Snippet } from "@nextui-org/react";
|
||||
import React from "react";
|
||||
|
||||
import { CopyIcon, DoneIcon } from "@/components/icons";
|
||||
|
||||
interface SnippetLabelProps {
|
||||
label: string;
|
||||
[key: string]: any;
|
||||
}
|
||||
export const SnippetLabel: React.FC<SnippetLabelProps> = ({
|
||||
label,
|
||||
...props
|
||||
}) => {
|
||||
return (
|
||||
label !== "" && (
|
||||
<Snippet
|
||||
className="m-0 flex items-center bg-transparent py-0"
|
||||
color="default"
|
||||
size="sm"
|
||||
radius="lg"
|
||||
hideSymbol
|
||||
copyIcon={<CopyIcon size={16} />}
|
||||
checkIcon={<DoneIcon size={16} />}
|
||||
{...props}
|
||||
>
|
||||
<p className="no-scrollbar text-md mb-1 w-32 overflow-hidden overflow-x-scroll text-ellipsis whitespace-nowrap text-sm font-semibold">
|
||||
{label}
|
||||
</p>
|
||||
</Snippet>
|
||||
)
|
||||
);
|
||||
};
|
||||
@@ -1,48 +1,18 @@
|
||||
"use client";
|
||||
|
||||
import { Card, CardBody, Divider, Tooltip } from "@nextui-org/react";
|
||||
import { Card, CardBody, Divider } from "@nextui-org/react";
|
||||
import { CircleUserRound } from "lucide-react";
|
||||
import { useState } from "react";
|
||||
|
||||
import { CopyIcon, DoneIcon } from "@/components/icons";
|
||||
import { CustomButton } from "@/components/ui/custom/custom-button";
|
||||
import { DateWithTime } from "@/components/ui/entities";
|
||||
import { DateWithTime, SnippetChip } from "@/components/ui/entities";
|
||||
import { UserDataWithRoles } from "@/types/users/users";
|
||||
|
||||
const TenantIdCopy = ({ id }: { id: string }) => {
|
||||
const [copied, setCopied] = useState(false);
|
||||
|
||||
const handleCopyTenantId = () => {
|
||||
navigator.clipboard.writeText(id);
|
||||
setCopied(true);
|
||||
setTimeout(() => setCopied(false), 2000);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className="flex items-center justify-between">
|
||||
<p className="text-sm font-semibold text-default-600">
|
||||
Active organization ID:
|
||||
</p>
|
||||
<div className="flex items-center">
|
||||
<Tooltip content={copied ? "Copied!" : "Copy ID"}>
|
||||
<CustomButton
|
||||
ariaLabel="Copy Tenant ID"
|
||||
onPress={handleCopyTenantId}
|
||||
variant="light"
|
||||
color="primary"
|
||||
size="sm"
|
||||
>
|
||||
<span className="mr-2 max-w-[120px] overflow-hidden overflow-ellipsis whitespace-nowrap">
|
||||
{id}
|
||||
</span>
|
||||
{copied ? (
|
||||
<DoneIcon size={16} className="text-success" />
|
||||
) : (
|
||||
<CopyIcon size={16} />
|
||||
)}
|
||||
</CustomButton>
|
||||
</Tooltip>
|
||||
</div>
|
||||
<SnippetChip value={id} />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user