import { useCallback } from "react"; import { faBan, faCheck, faCopy, faEdit, faEllipsisV, faExpand, faInfoCircle, faPlugCircleXmark, faSearch, faToggleOff, faToggleOn, faTrash, faWarning } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; import { useNavigate } from "@tanstack/react-router"; import { formatDistance } from "date-fns"; import { twMerge } from "tailwind-merge"; import { createNotification } from "@app/components/notifications"; import { ProjectPermissionCan } from "@app/components/permissions"; import { SecretScanningScanStatusBadge } from "@app/components/secret-scanning"; import { Badge, DropdownMenu, DropdownMenuContent, DropdownMenuItem, DropdownMenuTrigger, IconButton, Td, Tooltip, Tr } from "@app/components/v2"; import { ROUTE_PATHS } from "@app/const/routes"; import { ProjectPermissionSub } from "@app/context"; import { ProjectPermissionSecretScanningDataSourceActions } from "@app/context/ProjectPermissionContext/types"; import { RESOURCE_DESCRIPTION_HELPER, SECRET_SCANNING_DATA_SOURCE_MAP } from "@app/helpers/secretScanningV2"; import { useToggle } from "@app/hooks"; import { SecretScanningFindingStatus, SecretScanningScanStatus, TSecretScanningDataSourceWithDetails } from "@app/hooks/api/secretScanningV2"; type Props = { dataSource: TSecretScanningDataSourceWithDetails; onDelete: (dataSource: TSecretScanningDataSourceWithDetails) => void; onTriggerScan: (dataSource: TSecretScanningDataSourceWithDetails) => void; onToggleEnableAutoScan: (dataSource: TSecretScanningDataSourceWithDetails) => void; onEdit: (dataSource: TSecretScanningDataSourceWithDetails) => void; }; export const SecretScanningDataSourceRow = ({ dataSource, onDelete, onEdit, onTriggerScan, onToggleEnableAutoScan }: Props) => { const navigate = useNavigate(); const { id, name, description, isAutoScanEnabled, projectId, type, unresolvedFindings, lastScannedAt, lastScanStatus, lastScanStatusMessage, isDisconnected } = dataSource; const sourceDetails = SECRET_SCANNING_DATA_SOURCE_MAP[type]; const [isIdCopied, setIsIdCopied] = useToggle(false); const handleCopyId = useCallback(() => { setIsIdCopied.on(); navigator.clipboard.writeText(id); createNotification({ text: "Data Source ID copied to clipboard", type: "info" }); const timer = setTimeout(() => setIsIdCopied.off(), 2000); // eslint-disable-next-line consistent-return return () => clearTimeout(timer); }, [isIdCopied]); const autoScanDescription = RESOURCE_DESCRIPTION_HELPER[type]; return ( navigate({ to: ROUTE_PATHS.SecretScanning.DataSourceByIdPage.path, params: { dataSourceId: id, type, projectId } }) } className={twMerge( "group h-10 cursor-pointer transition-colors duration-100 hover:bg-mineshaft-700", lastScanStatus === SecretScanningScanStatus.Failed && "bg-red/5 hover:bg-red/10" )} key={`data-source-${id}`} >
{`${sourceDetails.name}

{sourceDetails.name}

{name}

{description && ( )}
{/* eslint-disable-next-line no-nested-ternary */} {lastScanStatus?.match(/queued|scanning/) ? ( Scanning For Leaks ) : // eslint-disable-next-line no-nested-ternary lastScannedAt ? ( // eslint-disable-next-line no-nested-ternary unresolvedFindings ? ( { e.stopPropagation(); navigate({ to: "/projects/secret-scanning/$projectId/findings", params: { projectId }, search: { search: name, status: SecretScanningFindingStatus.Unresolved } }); }} > {unresolvedFindings} Secret{unresolvedFindings > 1 ? "s" : ""} Detected ) : lastScanStatus === SecretScanningScanStatus.Failed ? ( No findings ) : ( No Secrets Detected ) ) : ( No findings )}
{/* eslint-disable-next-line no-nested-ternary */} {lastScanStatus?.match(/queued|scanning|failed/) ? ( ) : lastScannedAt ? ( {formatDistance(new Date(lastScannedAt), new Date(), { addSuffix: true })} ) : ( No scans )} {!isAutoScanEnabled && !isDisconnected && (
Auto-Scan Disabled
)} {isDisconnected && (
Disconnected
)}
} onClick={(e) => { e.stopPropagation(); handleCopyId(); }} > Copy Data Source ID {(isAllowed: boolean) => ( } onClick={(e) => { e.stopPropagation(); onTriggerScan(dataSource); }} isDisabled={!isAllowed} >
Trigger Scan
)}
{(isAllowed: boolean) => ( } onClick={(e) => { e.stopPropagation(); onToggleEnableAutoScan(dataSource); }} > {isAutoScanEnabled ? "Disable" : "Enable"} Auto-Scan )} {(isAllowed: boolean) => ( } onClick={(e) => { e.stopPropagation(); onEdit(dataSource); }} > Edit Data Source )} {(isAllowed: boolean) => ( } onClick={(e) => { e.stopPropagation(); onDelete(dataSource); }} > Delete Data Source )}
); };