import { useCallback } from "react"; import { faBan, faCheck, faCopy, faEllipsisV, faExpand, faInfoCircle, faSearch, 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 { ProjectPermissionSecretScanningDataSourceActions, ProjectPermissionSub } from "@app/context/ProjectPermissionContext/types"; import { RESOURCE_DESCRIPTION_HELPER } from "@app/helpers/secretScanningV2"; import { useToggle } from "@app/hooks"; import { SecretScanningFindingStatus, SecretScanningScanStatus, TSecretScanningDataSource, TSecretScanningResourceWithDetails, useTriggerSecretScanningDataSource } from "@app/hooks/api/secretScanningV2"; type Props = { resource: TSecretScanningResourceWithDetails; dataSource: TSecretScanningDataSource; }; export const SecretScanningResourceRow = ({ resource, dataSource }: Props) => { const { id, name, lastScannedAt, lastScanStatus, unresolvedFindings, lastScanStatusMessage } = resource; const { config: { includeRepos } } = dataSource; // scott: will need to be differentiated by type once other data sources are available const isActive = includeRepos.includes("*") || includeRepos.includes(name); const triggerDataSourceScan = useTriggerSecretScanningDataSource(); const navigate = useNavigate(); const handleTriggerScan = async () => { try { await triggerDataSourceScan.mutateAsync({ dataSourceId: dataSource.id, type: dataSource.type, projectId: dataSource.projectId, resourceId: id }); createNotification({ text: `Successfully triggered scan for ${name}`, type: "success" }); } catch { createNotification({ text: `Failed to trigger scan for ${name}`, type: "error" }); } }; const [isIdCopied, setIsIdCopied] = useToggle(false); const handleCopyId = useCallback( (idToCopy: string) => { setIsIdCopied.on(); navigator.clipboard.writeText(idToCopy); createNotification({ text: "Resource ID copied to clipboard", type: "info" }); const timer = setTimeout(() => setIsIdCopied.off(), 2000); // eslint-disable-next-line consistent-return return () => clearTimeout(timer); }, [isIdCopied] ); const resourceDetails = RESOURCE_DESCRIPTION_HELPER[dataSource.type]; return (
{name}