- );
-}
diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/CookieBannerCookiesPageLoader.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/CookieBannerCookiesPageLoader.tsx
deleted file mode 100644
index 66ef4c5b1..000000000
--- a/apps/console/src/pages/organizations/cookie-banners/configuration/cookies/CookieBannerCookiesPageLoader.tsx
+++ /dev/null
@@ -1,43 +0,0 @@
-// Copyright (c) 2026 Probo Inc .
-//
-// Permission to use, copy, modify, and/or distribute this software for any
-// purpose with or without fee is hereby granted, provided that the above
-// copyright notice and this permission notice appear in all copies.
-//
-// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
-// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
-// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
-// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
-// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
-// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
-// PERFORMANCE OF THIS SOFTWARE.
-
-import { Suspense, useEffect } from "react";
-import { useQueryLoader } from "react-relay";
-import { useParams } from "react-router";
-
-import type { CookieBannerCookiesPageQuery } from "#/__generated__/core/CookieBannerCookiesPageQuery.graphql";
-import { PageSkeleton } from "#/components/skeletons/PageSkeleton";
-
-import CookieBannerCookiesPage, { cookieBannerCookiesPageQuery } from "./CookieBannerCookiesPage";
-
-export default function CookieBannerCookiesPageLoader() {
- const { cookieBannerId } = useParams<{ cookieBannerId: string }>();
- const [queryRef, loadQuery] = useQueryLoader(cookieBannerCookiesPageQuery);
-
- useEffect(() => {
- if (cookieBannerId) {
- loadQuery({ cookieBannerId });
- }
- }, [loadQuery, cookieBannerId]);
-
- if (!queryRef) {
- return ;
- }
-
- return (
- }>
-
-
- );
-}
diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/detection/CookieBannerDetectionPage.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/detection/CookieBannerDetectionPage.tsx
index e34ddca96..64a89aeeb 100644
--- a/apps/console/src/pages/organizations/cookie-banners/configuration/detection/CookieBannerDetectionPage.tsx
+++ b/apps/console/src/pages/organizations/cookie-banners/configuration/detection/CookieBannerDetectionPage.tsx
@@ -19,6 +19,7 @@ import {
Option,
Select,
Tbody,
+ Th,
Thead,
Tr,
} from "@probo/ui";
@@ -77,6 +78,7 @@ const detectionFragment = graphql`
filters: ["filter", "orderBy"]
)
@required(action: THROW) {
+ __id
edges {
node {
id
@@ -110,6 +112,7 @@ export default function CookieBannerDetectionPage({
CookieBannerDetectionPageFragment$key
>(detectionFragment, data.node);
+ const connectionId = fragmentData.uncategorisedPatterns.__id;
const patterns = fragmentData.uncategorisedPatterns.edges.map(edge => edge.node) ?? [];
const refetchFilters = (overrides: Record = {}) => {
@@ -178,11 +181,16 @@ export default function CookieBannerDetectionPage({
{__("Source")}{__("Last Matched")}{__("Updated")}
+
);
}
diff --git a/apps/console/src/pages/organizations/cookie-banners/configuration/detection/_components/DetectionPatternRowEdit.tsx b/apps/console/src/pages/organizations/cookie-banners/configuration/detection/_components/DetectionPatternRowEdit.tsx
new file mode 100644
index 000000000..b611ad61c
--- /dev/null
+++ b/apps/console/src/pages/organizations/cookie-banners/configuration/detection/_components/DetectionPatternRowEdit.tsx
@@ -0,0 +1,108 @@
+// Copyright (c) 2026 Probo Inc .
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
+// OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+import { fromMaxAgeSeconds, toMaxAgeSeconds } from "@probo/helpers";
+import { useTranslate } from "@probo/i18n";
+import { Button, DurationInput, Input, Td, Tr } from "@probo/ui";
+import { Controller, useForm } from "react-hook-form";
+
+interface FormValues {
+ displayName: string;
+ duration: { value: string; unit: string };
+ description: string;
+}
+
+interface DetectionPatternRowEditProps {
+ displayName: string;
+ description: string;
+ maxAgeSeconds: number | null;
+ isUpdating: boolean;
+ onSave: (data: { displayName: string; description: string; maxAgeSeconds: number | null }) => void;
+ onCancel: () => void;
+}
+
+export function DetectionPatternRowEdit({
+ displayName,
+ description,
+ maxAgeSeconds,
+ isUpdating,
+ onSave,
+ onCancel,
+}: DetectionPatternRowEditProps) {
+ const { __ } = useTranslate();
+ const initial = fromMaxAgeSeconds(maxAgeSeconds);
+
+ const { register, handleSubmit, control } = useForm({
+ defaultValues: {
+ displayName,
+ duration: initial,
+ description,
+ },
+ });
+
+ const onSubmit = (data: FormValues) => {
+ onSave({
+ displayName: data.displayName,
+ description: data.description,
+ maxAgeSeconds: toMaxAgeSeconds(data.duration.value, data.duration.unit),
+ });
+ };
+
+ return (
+