"use client"; import { ColumnDef, Row, RowSelectionState } from "@tanstack/react-table"; import { Building2, FolderTree, Terminal } from "lucide-react"; import type { OrgWizardInitialData, ProviderWizardInitialData, } from "@/components/providers/wizard/types"; import { Badge, Tooltip, TooltipContent, TooltipTrigger, } from "@/components/shadcn"; import { Checkbox } from "@/components/shadcn/checkbox/checkbox"; import { CodeSnippet } from "@/components/shadcn/code-snippet/code-snippet"; import { DateWithTime, EntityInfo } from "@/components/shadcn/entities"; import { DataTableColumnHeader } from "@/components/shadcn/table"; import { DataTableExpandAllToggle } from "@/components/shadcn/table/data-table-expand-all-toggle"; import { DataTableExpandableCell } from "@/components/shadcn/table/data-table-expandable-cell"; import { getNodeLabel } from "@/lib/organizations"; import { isCloud } from "@/lib/shared/env"; import { isProvidersOrganizationRow, PROVIDERS_GROUP_KIND, ProvidersGroupKind, ProvidersProviderRow, ProvidersTableRow, } from "@/types/providers-table"; import { SCAN_CONFIGURATION_LIST_STATUS, ScanConfigurationData, type ScanConfigurationListStatus, } from "@/types/scan-configurations"; import type { ScanScheduleCapability, ScanScheduleProvider, } from "@/types/schedules"; import { LinkToScans } from "../link-to-scans"; import { DataTableRowActions } from "./data-table-row-actions"; interface GroupNameChipsProps { groupNames?: string[]; } const OrganizationIcon = ({ groupKind }: { groupKind: ProvidersGroupKind }) => { const Icon = groupKind === PROVIDERS_GROUP_KIND.ORGANIZATION ? Building2 : FolderTree; return (
); }; interface ProviderStatusCellProps { connected: boolean | null; isImported: boolean; } const IMPORTED_PROVIDER_TOOLTIP = "This provider has findings imported with the Prowler CLI"; const ImportedIndicator = () => { const indicator = ( ); return ( {indicator} {IMPORTED_PROVIDER_TOOLTIP} ); }; const ProviderStatusCell = ({ connected, isImported, }: ProviderStatusCellProps) => { let statusBadge; if (connected === true) { statusBadge = ( Connected ); } else if (connected === false) { statusBadge = ( Connection failed ); } else { statusBadge = ( Not connected ); } if (isImported) { return (
{statusBadge}
); } return statusBadge; }; function getSelectionLabel(row: Row): string | undefined { const isSelected = row.getIsSelected(); const isSomeSelected = row.getIsSomeSelected(); if (!isSelected && !isSomeSelected) return undefined; const subRows = row.subRows ?? []; const totalLeaves = countLeaves(subRows); const selectedLeaves = countSelectedLeaves(subRows); return `${selectedLeaves.toLocaleString()} of ${totalLeaves.toLocaleString()} Selected`; } function countLeaves(rows: Row[]): number { let count = 0; for (const row of rows) { if (row.subRows && row.subRows.length > 0) { count += countLeaves(row.subRows); } else { count++; } } return count; } function countSelectedLeaves(rows: Row[]): number { let count = 0; for (const row of rows) { if (row.subRows && row.subRows.length > 0) { count += countSelectedLeaves(row.subRows); } else if (row.getIsSelected()) { count++; } } return count; } export function getColumnProviders( rowSelection: RowSelectionState, testableProviderIds: string[], selectedScheduleProviderIds: string[], selectedScheduleProviders: ScanScheduleProvider[], onClearSelection: () => void, onOpenProviderWizard: (initialData?: ProviderWizardInitialData) => void, onOpenOrganizationWizard: (initialData: OrgWizardInitialData) => void, scanScheduleCapability?: ScanScheduleCapability, scanConfigs: ScanConfigurationData[] = [], scanConfigStatus: ScanConfigurationListStatus = SCAN_CONFIGURATION_LIST_STATUS.AVAILABLE, scanConfigIdByProviderId: ReadonlyMap = new Map(), ): ColumnDef[] { return [ { id: "account", size: 420, accessorFn: (row) => isProvidersOrganizationRow(row) ? row.name : row.attributes.alias, header: ({ column, table }) => (
table.toggleAllPageRowsSelected(checked === true) } onClick={(e) => e.stopPropagation()} aria-label="Select all" />
), cell: ({ row }) => { const isExpanded = row.getIsExpanded(); const checkboxSlot = ( row.toggleSelected(checked === true)} onClick={(e) => e.stopPropagation()} aria-label="Select row" /> ); if (isProvidersOrganizationRow(row.original)) { return ( } entityAlias={row.original.name} entityId={row.original.externalId ?? undefined} badge={getSelectionLabel(row)} showCopyAction /> ); } const provider = row.original; return ( Custom ) : undefined } /> ); }, }, { accessorKey: "groupNames", size: 160, header: ({ column }) => ( ), cell: ({ row }) => { if (isProvidersOrganizationRow(row.original)) { // Node label comes from the terminology table: node `kind` decides, // organization type is the fallback — never an ID prefix. const label = row.original.groupKind === PROVIDERS_GROUP_KIND.ORGANIZATION ? "Organization" : getNodeLabel(row.original.orgType, row.original.kind); return ( {label} ); } return ; }, enableSorting: false, }, { id: "lastScan", size: 160, header: ({ column }) => ( ), cell: ({ row }) => { if (isProvidersOrganizationRow(row.original)) { return -; } const provider = row.original as ProvidersProviderRow; const lastScanAt = provider.lastScanAt !== undefined ? provider.lastScanAt : provider.attributes.connection.last_checked_at; if (!lastScanAt) { return ( Never ); } return ; }, enableSorting: false, }, { id: "scanSchedule", size: 180, header: ({ column }) => ( ), cell: ({ row }) => { if (isProvidersOrganizationRow(row.original)) { return ( {row.original.providerCount} Providers ); } return ; }, enableSorting: false, }, { id: "status", size: 170, header: ({ column }) => ( ), cell: ({ row }) => { if (isProvidersOrganizationRow(row.original)) { return -; } return ( ); }, }, { accessorKey: "added", size: 140, header: ({ column }) => ( ), cell: ({ row }) => { if (isProvidersOrganizationRow(row.original)) { return -; } return ( ); }, }, { id: "actions", size: 56, header: ({ column }) => ( ), cell: ({ row }) => { const hasSelection = Object.values(rowSelection).some(Boolean); const currentScanConfigId = isProvidersOrganizationRow(row.original) ? null : (scanConfigIdByProviderId.get(row.original.id) ?? null); return ( ); }, enableSorting: false, }, ]; } export function GroupNameChips({ groupNames }: GroupNameChipsProps) { if (!groupNames || groupNames.length === 0) { return ( No groups ); } return (
{groupNames.map((name, index) => ( ))}
); }