feat(ui): add compliance provider-filter mode helper

- Detect and extract the provider-scope filter keys from search params
- Single source of truth for the scan vs provider-filter XOR

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
Pablo F.G
2026-06-22 10:10:59 +02:00
parent d90e4449f9
commit 7fd281cf02
2 changed files with 132 additions and 0 deletions
@@ -0,0 +1,86 @@
import { describe, expect, it } from "vitest";
import {
COMPLIANCE_PROVIDER_FILTER_KEYS,
extractComplianceProviderFilters,
hasComplianceProviderFilters,
} from "./compliance-provider-filters";
describe("COMPLIANCE_PROVIDER_FILTER_KEYS", () => {
it("contains the three provider scope keys", () => {
expect(COMPLIANCE_PROVIDER_FILTER_KEYS).toEqual([
"filter[provider_type__in]",
"filter[provider_id__in]",
"filter[provider_groups__in]",
]);
});
});
describe("hasComplianceProviderFilters", () => {
for (const key of COMPLIANCE_PROVIDER_FILTER_KEYS) {
it(`is true when ${key} is present (plain object)`, () => {
expect(hasComplianceProviderFilters({ [key]: "abc" })).toBe(true);
});
}
it("is true when reading from URLSearchParams", () => {
const params = new URLSearchParams();
params.set("filter[provider_groups__in]", "g1,g2");
expect(hasComplianceProviderFilters(params)).toBe(true);
});
it("is false for scanId / region / unrelated params", () => {
expect(
hasComplianceProviderFilters({
scanId: "scan-1",
"filter[region__in]": "eu-west-1",
}),
).toBe(false);
});
it("treats empty / whitespace values as absent", () => {
expect(
hasComplianceProviderFilters({
"filter[provider_type__in]": "",
"filter[provider_id__in]": " ",
}),
).toBe(false);
});
it("is false for an empty object", () => {
expect(hasComplianceProviderFilters({})).toBe(false);
});
});
describe("extractComplianceProviderFilters", () => {
it("returns only the present, non-empty provider keys", () => {
expect(
extractComplianceProviderFilters({
"filter[provider_type__in]": "aws,gcp",
"filter[provider_id__in]": "",
scanId: "scan-1",
"filter[region__in]": "eu-west-1",
}),
).toEqual({ "filter[provider_type__in]": "aws,gcp" });
});
it("joins array values with commas", () => {
expect(
extractComplianceProviderFilters({
"filter[provider_groups__in]": ["g1", "g2"],
}),
).toEqual({ "filter[provider_groups__in]": "g1,g2" });
});
it("reads from URLSearchParams", () => {
const params = new URLSearchParams();
params.set("filter[provider_id__in]", "p1,p2");
expect(extractComplianceProviderFilters(params)).toEqual({
"filter[provider_id__in]": "p1,p2",
});
});
it("returns an empty object when no provider filters are present", () => {
expect(extractComplianceProviderFilters({ scanId: "scan-1" })).toEqual({});
});
});
@@ -0,0 +1,46 @@
import type { SearchParamsProps } from "@/types/components";
/**
* Provider-scope filter keys the compliance UI sets. A subset of the API's
* `PROVIDER_FILTER_KEYS`; the backend (`ComplianceOverviewViewSet`) treats these
* as an alternative to `filter[scan_id]` (XOR) and aggregates compliance across
* the latest completed scan of each matching provider.
*/
export const COMPLIANCE_PROVIDER_FILTER_KEYS = [
"filter[provider_type__in]",
"filter[provider_id__in]",
"filter[provider_groups__in]",
] as const;
type SearchParamsLike = SearchParamsProps | URLSearchParams;
const readParam = (params: SearchParamsLike, key: string): string => {
if (params instanceof URLSearchParams) {
return params.get(key) ?? "";
}
const value = params[key];
if (Array.isArray(value)) return value.join(",");
return value ?? "";
};
/** True when any compliance provider-scope filter is present and non-empty. */
export const hasComplianceProviderFilters = (
params: SearchParamsLike,
): boolean =>
COMPLIANCE_PROVIDER_FILTER_KEYS.some(
(key) => readParam(params, key).trim().length > 0,
);
/** Returns only the present, non-empty provider-scope filters (CSV-joined). */
export const extractComplianceProviderFilters = (
params: SearchParamsLike,
): Record<string, string> => {
const result: Record<string, string> = {};
for (const key of COMPLIANCE_PROVIDER_FILTER_KEYS) {
const value = readParam(params, key).trim();
if (value.length > 0) {
result[key] = value;
}
}
return result;
};