import { ProviderProps, ProvidersApiResponse, ScanProps } from "@/types"; import { FilterEntity } from "@/types/filters"; import { ProviderConnectionStatus } from "@/types/providers"; import { ScanEntity } from "@/types/scans"; /** * Extracts normalized filters and search query from the URL search params. * Used Server Side Rendering (SSR). There is a hook (useUrlFilters) for client side. */ export const extractFiltersAndQuery = ( searchParams: Record, ) => { const filters: Record = { ...Object.fromEntries( Object.entries(searchParams) .filter(([key]) => key.startsWith("filter[")) .map(([key, value]) => [ key, Array.isArray(value) ? value.join(",") : value?.toString() || "", ]), ), }; const query = filters["filter[search]"] || ""; return { filters, query }; }; /** * Returns true if there are any scan or inserted_at filters in the search params. * Used to determine whether to call the full findings endpoint. */ export const hasDateOrScanFilter = (searchParams: Record) => Object.keys(searchParams).some( (key) => key.includes("inserted_at") || key.includes("scan__in"), ); /** * Encodes sort strings by removing leading "+" symbols. */ export const encodeSort = (sort?: string) => sort?.replace(/^\+/, "") || ""; /** * Extracts the sort string and the stable key to use in Suspense boundaries. */ export const extractSortAndKey = (searchParams: Record) => { const searchParamsKey = JSON.stringify(searchParams || {}); const rawSort = searchParams.sort?.toString(); const encodedSort = encodeSort(rawSort); return { searchParamsKey, rawSort, encodedSort }; }; /** * Replaces a specific field name inside a filter-style key of an object. * @param obj - The input object with filter-style keys (e.g., { 'filter[inserted_at]': '2025-05-21' }). * @param oldField - The field name to be replaced (e.g., 'inserted_at'). * @param newField - The field name to replace with (e.g., 'updated_at'). * @returns A new object with the updated filter key if a match is found. */ export function replaceFieldKey( obj: Record, oldField: string, newField: string, ): Record { const fieldObj: Record = {}; for (const key in obj) { const match = key.match(/^filter\[(.+)\]$/); if (match && match[1] === oldField) { const newKey = `filter[${newField}]`; fieldObj[newKey] = obj[key]; } else { fieldObj[key] = obj[key]; } } return fieldObj; } export const isScanEntity = (entity: ScanEntity) => { return entity && entity.providerInfo && entity.attributes; }; /** * Creates a scan details mapping for filters from completed scans. * Used to provide detailed information for scan filters in the UI. */ export const createScanDetailsMapping = ( completedScans: ScanProps[], providersData?: ProvidersApiResponse, ) => { if (!completedScans || completedScans.length === 0) { return []; } const scanMappings = completedScans.map((scan: ScanProps) => { // Get provider info from providerInfo if available, or find from providers data let providerInfo = scan.providerInfo; if (!providerInfo && scan.relationships?.provider?.data?.id) { const provider = providersData?.data?.find( (p: ProviderProps) => p.id === scan.relationships.provider.data.id, ); if (provider) { providerInfo = { provider: provider.attributes.provider, alias: provider.attributes.alias, uid: provider.attributes.uid, }; } } return { [scan.id]: { id: scan.id, providerInfo: { provider: providerInfo?.provider || "aws", alias: providerInfo?.alias, uid: providerInfo?.uid, }, attributes: { name: scan.attributes.name, completed_at: scan.attributes.completed_at, }, }, }; }); return scanMappings; }; // Helper to check if entity is a ProviderConnectionStatus (simple label/value object) export const isConnectionStatus = ( entity: FilterEntity, ): entity is ProviderConnectionStatus => { return !!(entity && "label" in entity && "value" in entity); }; /** * Connection status mapping for provider filters. * Maps boolean string values to user-friendly labels. */ export const CONNECTION_STATUS_MAPPING: Array<{ [key: string]: FilterEntity; }> = [ { true: { label: "Connected", value: "true" } as ProviderConnectionStatus, }, { false: { label: "Disconnected", value: "false", } as ProviderConnectionStatus, }, ];