+
{children}
),
@@ -300,5 +308,14 @@ describe("DataTableFilterCustom — batch vs instant mode", () => {
"wide",
);
});
+
+ it("should enable searchable filter dropdowns by default", () => {
+ render(
);
+
+ expect(screen.getByTestId("multiselect-content")).toHaveAttribute(
+ "data-search-placeholder",
+ "Search severity...",
+ );
+ });
});
});
diff --git a/ui/components/ui/table/data-table-filter-custom.tsx b/ui/components/ui/table/data-table-filter-custom.tsx
index 28988b34d8..6d0e0df33d 100644
--- a/ui/components/ui/table/data-table-filter-custom.tsx
+++ b/ui/components/ui/table/data-table-filter-custom.tsx
@@ -30,6 +30,10 @@ import {
import { DATA_TABLE_FILTER_MODE, DataTableFilterMode } from "@/types/filters";
import { ProviderConnectionStatus } from "@/types/providers";
+function isNonEmptyString(value: string | null | undefined): value is string {
+ return Boolean(value);
+}
+
export interface DataTableFilterCustomProps {
filters: FilterOption[];
/** Optional element to render at the start of the filters grid */
@@ -70,6 +74,14 @@ export const DataTableFilterCustom = ({
const { updateFilter } = useUrlFilters();
const searchParams = useSearchParams();
+ const buildSearchConfig = (filter: FilterOption) => {
+ const label = filter.labelCheckboxGroup.toLowerCase();
+ return {
+ placeholder: `Search ${label}...`,
+ emptyMessage: `No ${label} found.`,
+ };
+ };
+
// Helper function to get entity from valueLabelMapping
const getEntityForValue = (
filter: FilterOption,
@@ -124,6 +136,34 @@ export const DataTableFilterCustom = ({
);
};
+ const getSearchKeywords = (
+ entity: FilterEntity | undefined,
+ value: string,
+ displayLabel: string,
+ ): string[] => {
+ if (!entity) {
+ return [displayLabel, value];
+ }
+
+ if (isScanEntity(entity as ScanEntity)) {
+ const label = getScanEntityLabel(entity as ScanEntity);
+ return [displayLabel, value, label].filter(isNonEmptyString);
+ }
+
+ if (isConnectionStatus(entity)) {
+ return [displayLabel, value, (entity as ProviderConnectionStatus).label];
+ }
+
+ const providerEntity = entity as ProviderEntity;
+ return [
+ displayLabel,
+ value,
+ providerEntity.alias,
+ providerEntity.uid,
+ providerEntity.provider,
+ ].filter(isNonEmptyString);
+ };
+
// Sort filters by index property, with fallback to original order for filters without index
const sortedFilters = () => {
return [...filters].sort((a, b) => {
@@ -204,7 +244,7 @@ export const DataTableFilterCustom = ({
/>
Select All
@@ -219,6 +259,7 @@ export const DataTableFilterCustom = ({
key={value}
value={value}
badgeLabel={getBadgeLabel(entity, displayLabel)}
+ keywords={getSearchKeywords(entity, value, displayLabel)}
>
{entity ? renderEntityContent(entity) : displayLabel}