From 71a33e412bbbf588132400507f64b21a5200d9ea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=89mile=20R=C3=A9?= Date: Mon, 11 May 2026 15:34:24 +0400 Subject: [PATCH] Add tracker type filter and color-coded badges MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The trackers page now lets users filter by tracker type (Cookie, localStorage, sessionStorage, IndexedDB, Cache Storage) in addition to the existing source filter. Each tracker type and cookie source badge uses a distinct color for quick visual scanning. Signed-off-by: Émile Ré --- .../trackers/CookieBannerTrackersPage.tsx | 24 ++++++++++- .../_components/TrackerPatternRow.tsx | 43 +++++++++++-------- pkg/coredata/tracker_pattern_filter.go | 20 +++++++++ .../api/console/v1/cookie_banner_resolvers.go | 4 +- 4 files changed, 70 insertions(+), 21 deletions(-) diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/CookieBannerTrackersPage.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/CookieBannerTrackersPage.tsx index 10e76bc95..e41312a8a 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/CookieBannerTrackersPage.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/CookieBannerTrackersPage.tsx @@ -37,6 +37,7 @@ import type { CookieBannerTrackersPageRefetchQuery, CookieSource, TrackerPatternOrderField, + TrackerType, } from "#/__generated__/core/CookieBannerTrackersPageRefetchQuery.graphql"; import { SortableTable, SortableTh } from "#/components/SortableTable"; @@ -64,6 +65,7 @@ const trackersFragment = graphql` last: { type: "Int", defaultValue: null } query: { type: "String", defaultValue: null } source: { type: "CookieSource", defaultValue: null } + trackerType: { type: "TrackerType", defaultValue: null } ) { uncategorisedTrackerPatterns( first: $first @@ -71,7 +73,7 @@ const trackersFragment = graphql` last: $last before: $before orderBy: $order - filter: { query: $query, source: $source } + filter: { query: $query, source: $source, trackerType: $trackerType } ) @connection( key: "CookieBannerTrackersPage_uncategorisedTrackerPatterns" @@ -106,6 +108,7 @@ export default function CookieBannerTrackersPage({ const [isPending, startTransition] = useTransition(); const [queryFilter, setQueryFilter] = useState(""); const [sourceFilter, setSourceFilter] = useState(null); + const [trackerTypeFilter, setTrackerTypeFilter] = useState(null); const { data: fragmentData, ...pagination } = usePaginationFragment< CookieBannerTrackersPageRefetchQuery, @@ -121,6 +124,7 @@ export default function CookieBannerTrackersPage({ { query: queryFilter || null, source: sourceFilter, + trackerType: trackerTypeFilter, ...overrides, }, { fetchPolicy: "network-only" }, @@ -138,11 +142,18 @@ export default function CookieBannerTrackersPage({ refetchFilters({ source: newSource }); }; + const handleTrackerTypeFilterChange = (value: string) => { + const newType = value === "ALL" ? null : (value as TrackerType); + setTrackerTypeFilter(newType); + refetchFilters({ trackerType: newType }); + }; + const refetchWithFilters: ComponentProps["refetch"] = ({ order }) => { pagination.refetch({ order: { direction: order.direction, field: order.field as TrackerPatternOrderField }, query: queryFilter || null, source: sourceFilter, + trackerType: trackerTypeFilter, }); }; @@ -165,6 +176,17 @@ export default function CookieBannerTrackersPage({ +
diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx index a1d548e1f..64008e88f 100644 --- a/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx +++ b/apps/console/src/pages/organizations/cookie-banners/configuration/trackers/_components/TrackerPatternRow.tsx @@ -12,7 +12,7 @@ // OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR // PERFORMANCE OF THIS SOFTWARE. -import { Eye as IconEye, EyeSlash as IconEyeSlash } from "@phosphor-icons/react"; +import { EyeIcon, EyeSlashIcon } from "@phosphor-icons/react"; import { formatDate, formatError, type GraphQLError } from "@probo/helpers"; import { useTranslate } from "@probo/i18n"; import { @@ -124,14 +124,24 @@ const updatePatternMutation = graphql` } `; -function trackerTypeLabel(type: string, __: (s: string) => string): string { +type BadgeVariant = "success" | "warning" | "danger" | "info" | "neutral" | "outline" | "highlight"; + +function trackerTypeBadge(type: string, __: (s: string) => string): { label: string; variant: BadgeVariant } { switch (type) { - case "COOKIE": return __("Cookie"); - case "LOCAL_STORAGE": return __("localStorage"); - case "SESSION_STORAGE": return __("sessionStorage"); - case "INDEXED_DB": return __("IndexedDB"); - case "CACHE_STORAGE": return __("Cache Storage"); - default: return type; + case "COOKIE": return { label: __("Cookie"), variant: "warning" }; + case "LOCAL_STORAGE": return { label: __("localStorage"), variant: "info" }; + case "SESSION_STORAGE": return { label: __("sessionStorage"), variant: "highlight" }; + case "INDEXED_DB": return { label: __("IndexedDB"), variant: "success" }; + case "CACHE_STORAGE": return { label: __("Cache Storage"), variant: "outline" }; + default: return { label: type, variant: "neutral" }; + } +} + +function sourceBadge(source: string, __: (s: string) => string): { label: string; variant: BadgeVariant } { + switch (source) { + case "SCRIPT": return { label: __("Script"), variant: "info" }; + case "PRE_EXISTING": return { label: __("Pre-existing"), variant: "outline" }; + default: return { label: source, variant: "neutral" }; } } @@ -286,6 +296,9 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo ); } + const typeBadge = trackerTypeBadge(pattern.trackerType, __); + const srcBadge = pattern.source ? sourceBadge(pattern.source, __) : null; + return ( @@ -299,17 +312,11 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo
- - {trackerTypeLabel(pattern.trackerType, __)} - + {typeBadge.label} - {pattern.source - ? ( - - {pattern.source === "SCRIPT" ? __("Script") : __("Pre-existing")} - - ) + {srcBadge + ? {srcBadge.label} : -} @@ -360,7 +367,7 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo className="p-1 rounded cursor-pointer" title={pattern.excluded ? __("Include") : __("Exclude")} > - {pattern.excluded ? : } + {pattern.excluded ? : }