From 606aa3bdfec84f5091ebd0f4043f574e4ab91d24 Mon Sep 17 00:00:00 2001 From: Alejandro Bailo <59607668+alejandrobailo@users.noreply.github.com> Date: Wed, 11 Feb 2026 18:57:48 +0100 Subject: [PATCH] fix(ui): remove useTransition and shared context from useUrlFilters (#10025) (cherry picked from commit bcd7b2d72325ba12e5c151561c9effb51dd63691) # Conflicts: # ui/CHANGELOG.md # ui/hooks/use-url-filters.ts --- ui/CHANGELOG.md | 4 +++ ui/hooks/use-url-filters.ts | 65 ++++++++++++++++++++++++++++++++++--- 2 files changed, 64 insertions(+), 5 deletions(-) diff --git a/ui/CHANGELOG.md b/ui/CHANGELOG.md index 6418e73304..2b8f87db08 100644 --- a/ui/CHANGELOG.md +++ b/ui/CHANGELOG.md @@ -11,6 +11,10 @@ All notable changes to the **Prowler UI** are documented in this file. - Filter navigations not coordinating with Suspense boundaries due to missing startTransition in ProviderTypeSelector, AccountsSelector, and muted findings checkbox [(#10013)](https://github.com/prowler-cloud/prowler/pull/10013) - Scans page pagination not updating table data because ScansTableWithPolling kept stale state from initial mount [(#10013)](https://github.com/prowler-cloud/prowler/pull/10013) - Duplicate `filter[search]` parameter in findings and scans API calls [(#10013)](https://github.com/prowler-cloud/prowler/pull/10013) +<<<<<<< HEAD +======= +- All filters on `/findings` silently reverting on first click in production [(#10025)](https://github.com/prowler-cloud/prowler/pull/10025) +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) --- diff --git a/ui/hooks/use-url-filters.ts b/ui/hooks/use-url-filters.ts index 911aa61558..64da270c04 100644 --- a/ui/hooks/use-url-filters.ts +++ b/ui/hooks/use-url-filters.ts @@ -1,25 +1,27 @@ "use client"; import { usePathname, useRouter, useSearchParams } from "next/navigation"; +<<<<<<< HEAD import { useCallback, useTransition } from "react"; import { useFilterTransitionOptional } from "@/contexts"; +======= +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) /** * Custom hook to handle URL filters and automatically reset * pagination when filters change. * - * Uses useTransition to prevent full page reloads when filters change, - * keeping the current UI visible while the new data loads. - * - * When used within a FilterTransitionProvider, the transition state is shared - * across all components using this hook, enabling coordinated loading indicators. + * Uses client-side router navigation to update query params without + * full page reloads when filters change. */ export const useUrlFilters = () => { const router = useRouter(); const searchParams = useSearchParams(); const pathname = usePathname(); + const isPending = false; +<<<<<<< HEAD // Use shared context if available, otherwise fall back to local transition const sharedTransition = useFilterTransitionOptional(); const [localIsPending, localStartTransition] = useTransition(); @@ -27,6 +29,13 @@ export const useUrlFilters = () => { const isPending = sharedTransition?.isPending ?? localIsPending; const startTransition = sharedTransition?.startTransition ?? localStartTransition; +======= + const navigate = (params: URLSearchParams) => { + const queryString = params.toString(); + const targetUrl = queryString ? `${pathname}?${queryString}` : pathname; + router.push(targetUrl, { scroll: false }); + }; +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) const updateFilter = useCallback( (key: string, value: string | string[] | null) => { @@ -71,10 +80,15 @@ export const useUrlFilters = () => { params.delete(filterKey); +<<<<<<< HEAD // Only reset page to 1 if page parameter already exists if (params.has("page")) { params.set("page", "1"); } +======= + navigate(params); + }; +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) startTransition(() => { router.push(`${pathname}?${params.toString()}`, { scroll: false }); @@ -83,7 +97,21 @@ export const useUrlFilters = () => { [router, searchParams, pathname, startTransition], ); +<<<<<<< HEAD const clearAllFilters = useCallback(() => { +======= + params.delete(filterKey); + + // Only reset page to 1 if page parameter already exists + if (params.has("page")) { + params.set("page", "1"); + } + + navigate(params); + }; + + const clearAllFilters = () => { +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) const params = new URLSearchParams(searchParams.toString()); Array.from(params.keys()).forEach((key) => { if (key.startsWith("filter[") || key === "sort") { @@ -93,17 +121,44 @@ export const useUrlFilters = () => { params.delete("page"); +<<<<<<< HEAD startTransition(() => { router.push(`${pathname}?${params.toString()}`, { scroll: false }); }); }, [router, searchParams, pathname, startTransition]); +======= + navigate(params); + }; +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) const hasFilters = useCallback(() => { const params = new URLSearchParams(searchParams.toString()); return Array.from(params.keys()).some( (key) => key.startsWith("filter[") || key === "sort", ); +<<<<<<< HEAD }, [searchParams]); +======= + }; + + /** + * Low-level navigation function for complex filter updates that need + * to modify multiple params atomically (e.g., setting provider_type + * while clearing provider_id). The modifier receives a mutable + * URLSearchParams; page is auto-reset if already present. + */ + const navigateWithParams = (modifier: (params: URLSearchParams) => void) => { + const params = new URLSearchParams(searchParams.toString()); + modifier(params); + + // Only reset page to 1 if page parameter already exists + if (params.has("page")) { + params.set("page", "1"); + } + + navigate(params); + }; +>>>>>>> bcd7b2d72 (fix(ui): remove useTransition and shared context from useUrlFilters (#10025)) return { updateFilter,