Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions ui/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ All notable changes to the **Prowler UI** are documented in this file.
### 🔄 Changed

- Attack Paths custom openCypher queries now use a code editor with syntax highlighting and line numbers [(#10445)](https://github.com/prowler-cloud/prowler/pull/10445)
- Filter summary strip: removed redundant "Clear all" link next to pills (use top-bar Clear Filters instead) and switched chip variant from `outline` to `tag` for consistency [(#10481)](https://github.com/prowler-cloud/prowler/pull/10481)

### 🐞 Fixed

Expand Down
87 changes: 4 additions & 83 deletions ui/components/filters/filter-summary-strip.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,6 @@ import {
// TODO (E2E): Full filter strip flow should be covered in Playwright tests:
// - Filter chips appear after staging selections in the findings page
// - Removing a chip via the X button un-stages that filter value
// - "Clear all" removes all staged filter chips at once
// - Chips disappear after applying filters (pending state resets to URL state)
// ──────────────────────────────────────────────────────────────────────────

Expand All @@ -55,15 +54,10 @@ describe("FilterSummaryStrip", () => {
it("should not render anything", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
const { container } = render(
<FilterSummaryStrip
chips={[]}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
<FilterSummaryStrip chips={[]} onRemove={onRemove} />,
);

// Then
Expand All @@ -77,16 +71,9 @@ describe("FilterSummaryStrip", () => {
it("should render a chip for each filter value", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
render(
<FilterSummaryStrip
chips={mockChips}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);
render(<FilterSummaryStrip chips={mockChips} onRemove={onRemove} />);

// Then — 3 chips should be visible (2 severity + 1 status)
expect(screen.getAllByTestId("badge")).toHaveLength(3);
Expand All @@ -95,7 +82,6 @@ describe("FilterSummaryStrip", () => {
it("should display the label and value text for each chip", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
render(
Expand All @@ -108,7 +94,6 @@ describe("FilterSummaryStrip", () => {
},
]}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);

Expand All @@ -120,7 +105,6 @@ describe("FilterSummaryStrip", () => {
it("should display displayValue when provided instead of value", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
render(
Expand All @@ -134,7 +118,6 @@ describe("FilterSummaryStrip", () => {
},
]}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);

Expand All @@ -143,39 +126,12 @@ describe("FilterSummaryStrip", () => {
expect(screen.queryByText("FAIL")).not.toBeInTheDocument();
});

it("should render a 'Clear all' button", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
render(
<FilterSummaryStrip
chips={mockChips}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);

// Then
expect(
screen.getByRole("button", { name: "Clear all" }),
).toBeInTheDocument();
});

it("should render an aria-label region for accessibility", () => {
// Given
const onRemove = vi.fn();
const onClearAll = vi.fn();

// When
render(
<FilterSummaryStrip
chips={mockChips}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);
render(<FilterSummaryStrip chips={mockChips} onRemove={onRemove} />);

// Then
expect(
Expand All @@ -191,7 +147,6 @@ describe("FilterSummaryStrip", () => {
// Given
const user = userEvent.setup();
const onRemove = vi.fn();
const onClearAll = vi.fn();

render(
<FilterSummaryStrip
Expand All @@ -203,7 +158,6 @@ describe("FilterSummaryStrip", () => {
},
]}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);

Expand All @@ -222,15 +176,8 @@ describe("FilterSummaryStrip", () => {
// Given
const user = userEvent.setup();
const onRemove = vi.fn();
const onClearAll = vi.fn();

render(
<FilterSummaryStrip
chips={mockChips}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);
render(<FilterSummaryStrip chips={mockChips} onRemove={onRemove} />);

// When — click the X button for "high" severity
const removeHighButton = screen.getByRole("button", {
Expand All @@ -243,30 +190,4 @@ describe("FilterSummaryStrip", () => {
expect(onRemove).toHaveBeenCalledTimes(1);
});
});

// ── onClearAll interaction ───────────────────────────────────────────────

describe("onClearAll", () => {
it("should call onClearAll when 'Clear all' is clicked", async () => {
// Given
const user = userEvent.setup();
const onRemove = vi.fn();
const onClearAll = vi.fn();

render(
<FilterSummaryStrip
chips={mockChips}
onRemove={onRemove}
onClearAll={onClearAll}
/>,
);

// When
await user.click(screen.getByRole("button", { name: "Clear all" }));

// Then
expect(onClearAll).toHaveBeenCalledTimes(1);
expect(onRemove).not.toHaveBeenCalled();
});
});
});
14 changes: 1 addition & 13 deletions ui/components/filters/filter-summary-strip.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,6 @@ export interface FilterSummaryStripProps {
chips: FilterChip[];
/** Called when the user clicks the X on a chip */
onRemove: (key: string, value: string) => void;
/** Called when the user clicks "Clear all" */
onClearAll: () => void;
/** Optional extra class names for the outer wrapper */
className?: string;
}
Expand All @@ -33,13 +31,11 @@ export interface FilterSummaryStripProps {
*
* - Hidden when `chips` is empty.
* - Each chip carries its own X button to remove that single value.
* - A "Clear all" link removes everything at once.
* - Reusable: no Findings-specific logic, driven entirely by props.
*/
export const FilterSummaryStrip = ({
chips,
onRemove,
onClearAll,
className,
}: FilterSummaryStripProps) => {
if (chips.length === 0) return null;
Expand All @@ -54,7 +50,7 @@ export const FilterSummaryStrip = ({
{chips.map((chip) => (
<Badge
key={`${chip.key}-${chip.value}`}
variant="outline"
variant="tag"
className="flex items-center gap-1 pr-1"
>
<span className="text-text-neutral-primary text-xs">
Expand All @@ -71,14 +67,6 @@ export const FilterSummaryStrip = ({
</button>
</Badge>
))}

<button
type="button"
onClick={onClearAll}
className="text-text-neutral-secondary hover:text-text-neutral-primary text-xs underline-offset-2 hover:underline focus-visible:ring-1 focus-visible:ring-offset-1 focus-visible:outline-none"
>
Clear all
</button>
</div>
);
};
21 changes: 1 addition & 20 deletions ui/components/findings/findings-filters.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,6 @@ export const FindingsFilters = ({
applyAll,
discardAll,
clearAndApply,
clearKeys,
hasChanges,
changeCount,
getFilterValue,
Expand Down Expand Up @@ -199,20 +198,6 @@ export const FindingsFilters = ({
setPending(filterKey, nextValues);
};

// Handler for clearing all chips: clears only the filter keys visible as chips,
// without touching provider/account selectors.
const PROVIDER_KEYS = new Set([
"filter[provider_type__in]",
"filter[provider_id__in]",
]);

const handleClearAllChips = () => {
const chipKeys = Array.from(new Set(filterChips.map((c) => c.key))).filter(
(k) => !PROVIDER_KEYS.has(k),
);
clearKeys(chipKeys);
};

// Derive pending muted state for the checkbox.
// Note: "filter[muted]" participates in batch mode — applyAll includes it
// when present in pending state, and the defaultParams option ensures
Expand Down Expand Up @@ -291,11 +276,7 @@ export const FindingsFilters = ({
</div>

{/* Summary strip: shown below filter bar when there are pending changes */}
<FilterSummaryStrip
chips={filterChips}
onRemove={handleChipRemove}
onClearAll={handleClearAllChips}
/>
<FilterSummaryStrip chips={filterChips} onRemove={handleChipRemove} />

{/* Expandable filters section */}
{hasCustomFilters && (
Expand Down
Loading
Loading