mirror of
https://github.com/prowler-cloud/prowler.git
synced 2025-12-19 05:17:47 +00:00
Compare commits
1 Commits
ed3fd72e70
...
feat/ui-sc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
078d4de2be |
@@ -1,35 +0,0 @@
|
||||
"use client";
|
||||
|
||||
import { X } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { Badge } from "@/components/shadcn";
|
||||
import { useUrlFilters } from "@/hooks/use-url-filters";
|
||||
|
||||
export const ActiveCheckIdFilter = () => {
|
||||
const searchParams = useSearchParams();
|
||||
const { clearFilter } = useUrlFilters();
|
||||
|
||||
const checkIdFilter = searchParams.get("filter[check_id__in]");
|
||||
|
||||
if (!checkIdFilter) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const checkIds = checkIdFilter.split(",");
|
||||
const displayText =
|
||||
checkIds.length > 1
|
||||
? `${checkIds.length} Check IDs filtered`
|
||||
: `Check ID: ${checkIds[0]}`;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="flex cursor-pointer items-center gap-1 px-3 py-1.5"
|
||||
onClick={() => clearFilter("check_id__in")}
|
||||
>
|
||||
<span className="max-w-[200px] truncate text-sm">{displayText}</span>
|
||||
<X className="size-3.5 shrink-0" />
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
90
ui/components/filters/active-filter-badge.tsx
Normal file
90
ui/components/filters/active-filter-badge.tsx
Normal file
@@ -0,0 +1,90 @@
|
||||
"use client";
|
||||
|
||||
import { X } from "lucide-react";
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { Badge } from "@/components/shadcn";
|
||||
import { useUrlFilters } from "@/hooks/use-url-filters";
|
||||
|
||||
export interface ActiveFilterBadgeProps {
|
||||
/**
|
||||
* The filter key without the "filter[]" wrapper.
|
||||
* Example: "scan__in", "check_id__in", "provider__in"
|
||||
*/
|
||||
filterKey: string;
|
||||
|
||||
/**
|
||||
* Label to display before the value.
|
||||
* Example: "Scan", "Check ID", "Provider"
|
||||
*/
|
||||
label: string;
|
||||
|
||||
/**
|
||||
* Optional function to format a single value for display.
|
||||
* Useful for truncating UUIDs, etc.
|
||||
* Default: shows value as-is
|
||||
*/
|
||||
formatValue?: (value: string) => string;
|
||||
|
||||
/**
|
||||
* Optional function to format the display when multiple values are selected.
|
||||
* Default: "{count} {label}s filtered"
|
||||
*/
|
||||
formatMultiple?: (count: number, label: string) => string;
|
||||
}
|
||||
|
||||
export const ActiveFilterBadge = ({
|
||||
filterKey,
|
||||
label,
|
||||
formatValue = (v) => v,
|
||||
formatMultiple = (count, lbl) => `${count} ${lbl}s filtered`,
|
||||
}: ActiveFilterBadgeProps) => {
|
||||
const searchParams = useSearchParams();
|
||||
const { clearFilter } = useUrlFilters();
|
||||
|
||||
const fullKey = filterKey.startsWith("filter[")
|
||||
? filterKey
|
||||
: `filter[${filterKey}]`;
|
||||
|
||||
const filterValue = searchParams.get(fullKey);
|
||||
|
||||
if (!filterValue) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const values = filterValue.split(",");
|
||||
const displayText =
|
||||
values.length > 1
|
||||
? formatMultiple(values.length, label)
|
||||
: `${label}: ${formatValue(values[0])}`;
|
||||
|
||||
return (
|
||||
<Badge
|
||||
variant="outline"
|
||||
className="flex cursor-pointer items-center gap-1 px-3 py-1.5"
|
||||
onClick={() => clearFilter(filterKey)}
|
||||
>
|
||||
<span className="max-w-[200px] truncate text-sm">{displayText}</span>
|
||||
<X className="size-3.5 shrink-0" />
|
||||
</Badge>
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Pre-configured filter badges for common use cases
|
||||
*/
|
||||
export const ScanFilterBadge = () => (
|
||||
<ActiveFilterBadge
|
||||
filterKey="scan__in"
|
||||
label="Scan"
|
||||
formatValue={(id) => `${id.slice(0, 8)}...`}
|
||||
/>
|
||||
);
|
||||
|
||||
export const CheckIdFilterBadge = () => (
|
||||
<ActiveFilterBadge
|
||||
filterKey="check_id__in"
|
||||
label="Check ID"
|
||||
formatMultiple={(count) => `${count} Check IDs filtered`}
|
||||
/>
|
||||
);
|
||||
@@ -1,4 +1,4 @@
|
||||
export * from "./active-check-id-filter";
|
||||
export * from "./active-filter-badge";
|
||||
export * from "./clear-filters-button";
|
||||
export * from "./custom-account-selection";
|
||||
export * from "./custom-checkbox-muted-findings";
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
"use client";
|
||||
|
||||
import { ColumnDef } from "@tanstack/react-table";
|
||||
import { ColumnDef, Row } from "@tanstack/react-table";
|
||||
import Link from "next/link";
|
||||
import { useRouter, useSearchParams } from "next/navigation";
|
||||
|
||||
import { InfoIcon } from "@/components/icons";
|
||||
import { Button } from "@/components/shadcn";
|
||||
import { TableLink } from "@/components/ui/custom";
|
||||
import { DateWithTime, EntityInfo } from "@/components/ui/entities";
|
||||
import { TriggerSheet } from "@/components/ui/sheet";
|
||||
@@ -19,7 +21,7 @@ const getScanData = (row: { original: ScanProps }) => {
|
||||
return row.original;
|
||||
};
|
||||
|
||||
const ScanDetailsCell = ({ row }: { row: any }) => {
|
||||
const ScanDetailsCell = ({ row }: { row: Row<ScanProps> }) => {
|
||||
const router = useRouter();
|
||||
const searchParams = useSearchParams();
|
||||
const scanId = searchParams.get("scanId");
|
||||
@@ -192,11 +194,28 @@ export const ColumnGetScans: ColumnDef<ScanProps>[] = [
|
||||
),
|
||||
cell: ({ row }) => {
|
||||
const {
|
||||
attributes: { unique_resource_count },
|
||||
id,
|
||||
attributes: { unique_resource_count, state },
|
||||
} = getScanData(row);
|
||||
const isCompleted = state === "completed";
|
||||
|
||||
if (!isCompleted) {
|
||||
return (
|
||||
<div className="flex w-fit items-center justify-center">
|
||||
<span className="text-default-500 text-xs font-medium">
|
||||
{unique_resource_count ?? "-"}
|
||||
</span>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="flex w-fit items-center justify-center">
|
||||
<span className="text-xs font-medium">{unique_resource_count}</span>
|
||||
<Button asChild variant="link" size="sm" className="text-xs">
|
||||
<Link href={`/resources?filter[scan__in]=${id}`}>
|
||||
{unique_resource_count}
|
||||
</Link>
|
||||
</Button>
|
||||
</div>
|
||||
);
|
||||
},
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
import { useSearchParams } from "next/navigation";
|
||||
|
||||
import { ComplianceScanInfo } from "@/components/compliance/compliance-header/compliance-scan-info";
|
||||
import { ActiveCheckIdFilter } from "@/components/filters/active-check-id-filter";
|
||||
import {
|
||||
CheckIdFilterBadge,
|
||||
ScanFilterBadge,
|
||||
} from "@/components/filters/active-filter-badge";
|
||||
import { ClearFiltersButton } from "@/components/filters/clear-filters-button";
|
||||
import {
|
||||
MultiSelect,
|
||||
@@ -165,8 +168,9 @@ export const DataTableFilterCustom = ({
|
||||
</MultiSelect>
|
||||
);
|
||||
})}
|
||||
<div className="flex items-center justify-start gap-2">
|
||||
<ActiveCheckIdFilter />
|
||||
<div className="flex flex-wrap items-center justify-start gap-2">
|
||||
<ScanFilterBadge />
|
||||
<CheckIdFilterBadge />
|
||||
<ClearFiltersButton />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user