@@ -30,8 +30,8 @@ export const cookieBannerDisplayPageQuery = graphql`
|
|||||||
__typename
|
__typename
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
id
|
id
|
||||||
consentCategories(first: 50, orderBy: { field: RANK, direction: ASC })
|
categories(first: 50, orderBy: { field: RANK, direction: ASC }, filter: { excludeKind: UNCATEGORISED })
|
||||||
@connection(key: "CookieBannerDisplayPage_consentCategories")
|
@connection(key: "CookieBannerDisplayPage_categories")
|
||||||
@required(action: THROW) {
|
@required(action: THROW) {
|
||||||
__id
|
__id
|
||||||
edges {
|
edges {
|
||||||
@@ -63,8 +63,8 @@ export default function CookieBannerDisplayPage({
|
|||||||
}
|
}
|
||||||
|
|
||||||
const banner = data.node;
|
const banner = data.node;
|
||||||
const connectionId = banner.consentCategories.__id;
|
const connectionId = banner.categories.__id;
|
||||||
const categories = banner.consentCategories.edges.map(e => e.node);
|
const categories = banner.categories.edges.map(e => e.node);
|
||||||
|
|
||||||
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
const [showCreateDialog, setShowCreateDialog] = useState(false);
|
||||||
|
|
||||||
|
|||||||
@@ -85,7 +85,7 @@ export const categorySectionFragment = graphql`
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
cookieBanner @required(action: THROW) {
|
cookieBanner @required(action: THROW) {
|
||||||
consentCategories(first: 50, orderBy: { field: RANK, direction: ASC }) @required(action: THROW) {
|
categories(first: 50, orderBy: { field: RANK, direction: ASC }, filter: { excludeKind: UNCATEGORISED }) @required(action: THROW) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@@ -252,7 +252,7 @@ const reorderCategoryMutation = graphql`
|
|||||||
reorderCookieCategory(input: $input) {
|
reorderCookieCategory(input: $input) {
|
||||||
cookieBanner {
|
cookieBanner {
|
||||||
id
|
id
|
||||||
consentCategories(first: 50, orderBy: { field: RANK, direction: ASC }) {
|
categories(first: 50, orderBy: { field: RANK, direction: ASC }, filter: { excludeKind: UNCATEGORISED }) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@@ -517,7 +517,7 @@ export function CategorySection({ categoryKey, connectionId }: CategorySectionPr
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
const allCategories = category.cookieBanner.consentCategories.edges.map(e => e.node) ?? [];
|
const allCategories = category.cookieBanner.categories.edges.map(e => e.node) ?? [];
|
||||||
const siblingCategories = allCategories.filter(c => c.id !== category.id);
|
const siblingCategories = allCategories.filter(c => c.id !== category.id);
|
||||||
const selfIndex = allCategories.findIndex(c => c.id === category.id);
|
const selfIndex = allCategories.findIndex(c => c.id === category.id);
|
||||||
const isFirst = selfIndex === 0;
|
const isFirst = selfIndex === 0;
|
||||||
|
|||||||
@@ -49,6 +49,15 @@ export const cookieBannerTrackersPageQuery = graphql`
|
|||||||
__typename
|
__typename
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
...CookieBannerTrackersPageFragment
|
...CookieBannerTrackersPageFragment
|
||||||
|
categories(first: 50, orderBy: { field: RANK, direction: ASC })
|
||||||
|
@required(action: THROW) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -66,17 +75,18 @@ const trackersFragment = graphql`
|
|||||||
query: { type: "String", defaultValue: null }
|
query: { type: "String", defaultValue: null }
|
||||||
source: { type: "CookieSource", defaultValue: null }
|
source: { type: "CookieSource", defaultValue: null }
|
||||||
trackerType: { type: "TrackerType", defaultValue: null }
|
trackerType: { type: "TrackerType", defaultValue: null }
|
||||||
|
cookieCategoryId: { type: "ID", defaultValue: null }
|
||||||
) {
|
) {
|
||||||
uncategorisedTrackerPatterns(
|
trackerPatterns(
|
||||||
first: $first
|
first: $first
|
||||||
after: $after
|
after: $after
|
||||||
last: $last
|
last: $last
|
||||||
before: $before
|
before: $before
|
||||||
orderBy: $order
|
orderBy: $order
|
||||||
filter: { query: $query, source: $source, trackerType: $trackerType }
|
filter: { query: $query, source: $source, trackerType: $trackerType, cookieCategoryId: $cookieCategoryId }
|
||||||
)
|
)
|
||||||
@connection(
|
@connection(
|
||||||
key: "CookieBannerTrackersPage_uncategorisedTrackerPatterns"
|
key: "CookieBannerTrackersPage_trackerPatterns"
|
||||||
filters: ["filter", "orderBy"]
|
filters: ["filter", "orderBy"]
|
||||||
)
|
)
|
||||||
@required(action: THROW) {
|
@required(action: THROW) {
|
||||||
@@ -109,14 +119,19 @@ export default function CookieBannerTrackersPage({
|
|||||||
const [queryFilter, setQueryFilter] = useState("");
|
const [queryFilter, setQueryFilter] = useState("");
|
||||||
const [sourceFilter, setSourceFilter] = useState<CookieSource | null>(null);
|
const [sourceFilter, setSourceFilter] = useState<CookieSource | null>(null);
|
||||||
const [trackerTypeFilter, setTrackerTypeFilter] = useState<TrackerType | null>(null);
|
const [trackerTypeFilter, setTrackerTypeFilter] = useState<TrackerType | null>(null);
|
||||||
|
const [categoryFilter, setCategoryFilter] = useState<string | null>(null);
|
||||||
|
|
||||||
const { data: fragmentData, ...pagination } = usePaginationFragment<
|
const { data: fragmentData, ...pagination } = usePaginationFragment<
|
||||||
CookieBannerTrackersPageRefetchQuery,
|
CookieBannerTrackersPageRefetchQuery,
|
||||||
CookieBannerTrackersPageFragment$key
|
CookieBannerTrackersPageFragment$key
|
||||||
>(trackersFragment, data.node);
|
>(trackersFragment, data.node);
|
||||||
|
|
||||||
const connectionId = fragmentData.uncategorisedTrackerPatterns.__id;
|
const connectionId = fragmentData.trackerPatterns.__id;
|
||||||
const patterns = fragmentData.uncategorisedTrackerPatterns.edges.map(edge => edge.node) ?? [];
|
const patterns = fragmentData.trackerPatterns.edges.map(edge => edge.node) ?? [];
|
||||||
|
|
||||||
|
const categories = data.node.__typename === "CookieBanner"
|
||||||
|
? data.node.categories.edges.map(edge => edge.node)
|
||||||
|
: [];
|
||||||
|
|
||||||
const refetchFilters = (overrides: Record<string, unknown> = {}) => {
|
const refetchFilters = (overrides: Record<string, unknown> = {}) => {
|
||||||
startTransition(() => {
|
startTransition(() => {
|
||||||
@@ -125,6 +140,7 @@ export default function CookieBannerTrackersPage({
|
|||||||
query: queryFilter || null,
|
query: queryFilter || null,
|
||||||
source: sourceFilter,
|
source: sourceFilter,
|
||||||
trackerType: trackerTypeFilter,
|
trackerType: trackerTypeFilter,
|
||||||
|
cookieCategoryId: categoryFilter,
|
||||||
...overrides,
|
...overrides,
|
||||||
},
|
},
|
||||||
{ fetchPolicy: "network-only" },
|
{ fetchPolicy: "network-only" },
|
||||||
@@ -148,12 +164,19 @@ export default function CookieBannerTrackersPage({
|
|||||||
refetchFilters({ trackerType: newType });
|
refetchFilters({ trackerType: newType });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const handleCategoryFilterChange = (value: string) => {
|
||||||
|
const newCategory = value === "ALL" ? null : value;
|
||||||
|
setCategoryFilter(newCategory);
|
||||||
|
refetchFilters({ cookieCategoryId: newCategory });
|
||||||
|
};
|
||||||
|
|
||||||
const refetchWithFilters: ComponentProps<typeof SortableTable>["refetch"] = ({ order }) => {
|
const refetchWithFilters: ComponentProps<typeof SortableTable>["refetch"] = ({ order }) => {
|
||||||
pagination.refetch({
|
pagination.refetch({
|
||||||
order: { direction: order.direction, field: order.field as TrackerPatternOrderField },
|
order: { direction: order.direction, field: order.field as TrackerPatternOrderField },
|
||||||
query: queryFilter || null,
|
query: queryFilter || null,
|
||||||
source: sourceFilter,
|
source: sourceFilter,
|
||||||
trackerType: trackerTypeFilter,
|
trackerType: trackerTypeFilter,
|
||||||
|
cookieCategoryId: categoryFilter,
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -187,6 +210,15 @@ export default function CookieBannerTrackersPage({
|
|||||||
<Option value="SCRIPT">{__("Script")}</Option>
|
<Option value="SCRIPT">{__("Script")}</Option>
|
||||||
<Option value="PRE_EXISTING">{__("Pre-existing")}</Option>
|
<Option value="PRE_EXISTING">{__("Pre-existing")}</Option>
|
||||||
</Select>
|
</Select>
|
||||||
|
<Select
|
||||||
|
value={categoryFilter ?? "ALL"}
|
||||||
|
onValueChange={handleCategoryFilterChange}
|
||||||
|
>
|
||||||
|
<Option value="ALL">{__("All categories")}</Option>
|
||||||
|
{categories.map(category => (
|
||||||
|
<Option key={category.id} value={category.id}>{category.name}</Option>
|
||||||
|
))}
|
||||||
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className={isPending ? "opacity-50 pointer-events-none transition-opacity" : ""}>
|
<div className={isPending ? "opacity-50 pointer-events-none transition-opacity" : ""}>
|
||||||
@@ -202,6 +234,7 @@ export default function CookieBannerTrackersPage({
|
|||||||
<SortableTh field="NAME">{__("Name")}</SortableTh>
|
<SortableTh field="NAME">{__("Name")}</SortableTh>
|
||||||
<Th>{__("Type")}</Th>
|
<Th>{__("Type")}</Th>
|
||||||
<SortableTh field="SOURCE">{__("Source")}</SortableTh>
|
<SortableTh field="SOURCE">{__("Source")}</SortableTh>
|
||||||
|
<Th>{__("Category")}</Th>
|
||||||
<SortableTh field="LAST_MATCHED_AT">{__("Last Matched")}</SortableTh>
|
<SortableTh field="LAST_MATCHED_AT">{__("Last Matched")}</SortableTh>
|
||||||
<Th className="w-28" />
|
<Th className="w-28" />
|
||||||
</Tr>
|
</Tr>
|
||||||
@@ -221,10 +254,10 @@ export default function CookieBannerTrackersPage({
|
|||||||
<Card padded>
|
<Card padded>
|
||||||
<div className="text-center py-12">
|
<div className="text-center py-12">
|
||||||
<h3 className="text-lg font-semibold mb-2">
|
<h3 className="text-lg font-semibold mb-2">
|
||||||
{__("No uncategorised patterns")}
|
{__("No tracker patterns")}
|
||||||
</h3>
|
</h3>
|
||||||
<p className="text-txt-tertiary">
|
<p className="text-txt-tertiary">
|
||||||
{__("All detected cookie patterns have been categorised. New patterns will appear here when detected.")}
|
{__("No cookie patterns have been detected yet. Patterns will appear here when detected.")}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</Card>
|
</Card>
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ export const moveToCategoryDropdownQuery = graphql`
|
|||||||
node(id: $cookieBannerId) @required(action: THROW) {
|
node(id: $cookieBannerId) @required(action: THROW) {
|
||||||
__typename
|
__typename
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
consentCategories(first: 50, orderBy: { field: RANK, direction: ASC })
|
categories(first: 50, orderBy: { field: RANK, direction: ASC })
|
||||||
@required(action: THROW) {
|
@required(action: THROW) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@@ -53,7 +53,7 @@ export function MoveToCategoryDropdown({
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const categories = data.node.consentCategories.edges.map(e => e.node);
|
const categories = data.node.categories.edges.map(e => e.node);
|
||||||
|
|
||||||
if (categories.length === 0) {
|
if (categories.length === 0) {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@@ -53,6 +53,9 @@ const trackerPatternFragment = graphql`
|
|||||||
maxAgeSeconds
|
maxAgeSeconds
|
||||||
excluded
|
excluded
|
||||||
lastMatchedAt
|
lastMatchedAt
|
||||||
|
cookieCategory {
|
||||||
|
name
|
||||||
|
}
|
||||||
}
|
}
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -316,6 +319,11 @@ export function TrackerPatternRow({ patternKey, connectionId }: TrackerPatternRo
|
|||||||
? <Badge variant={srcBadge.variant}>{srcBadge.label}</Badge>
|
? <Badge variant={srcBadge.variant}>{srcBadge.label}</Badge>
|
||||||
: <span className="text-txt-tertiary">-</span>}
|
: <span className="text-txt-tertiary">-</span>}
|
||||||
</Td>
|
</Td>
|
||||||
|
<Td>
|
||||||
|
{pattern.cookieCategory
|
||||||
|
? <span>{pattern.cookieCategory.name}</span>
|
||||||
|
: <span className="text-txt-tertiary">-</span>}
|
||||||
|
</Td>
|
||||||
<Td>
|
<Td>
|
||||||
{pattern.lastMatchedAt
|
{pattern.lastMatchedAt
|
||||||
? (
|
? (
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ export function TrackerPatternRowEdit({
|
|||||||
<span className="font-medium">{pattern}</span>
|
<span className="font-medium">{pattern}</span>
|
||||||
</Td>
|
</Td>
|
||||||
<Td />
|
<Td />
|
||||||
|
<Td />
|
||||||
<Td className="pr-3">
|
<Td className="pr-3">
|
||||||
<Controller
|
<Controller
|
||||||
name="duration"
|
name="duration"
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export const cookieBannerTranslationsPageQuery = graphql`
|
|||||||
language
|
language
|
||||||
translations
|
translations
|
||||||
}
|
}
|
||||||
consentCategories(first: 50, orderBy: { field: RANK, direction: ASC }) @required(action: THROW) {
|
categories(first: 50, orderBy: { field: RANK, direction: ASC }, filter: { excludeKind: UNCATEGORISED }) @required(action: THROW) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@@ -101,14 +101,14 @@ export default function CookieBannerTranslationsPage({
|
|||||||
|
|
||||||
const categories = useMemo(
|
const categories = useMemo(
|
||||||
() =>
|
() =>
|
||||||
banner.consentCategories.edges.map(e => ({
|
banner.categories.edges.map(e => ({
|
||||||
id: e.node.id,
|
id: e.node.id,
|
||||||
name: e.node.name,
|
name: e.node.name,
|
||||||
slug: e.node.slug,
|
slug: e.node.slug,
|
||||||
description: e.node.description,
|
description: e.node.description,
|
||||||
kind: e.node.kind,
|
kind: e.node.kind,
|
||||||
})),
|
})),
|
||||||
[banner.consentCategories],
|
[banner.categories],
|
||||||
);
|
);
|
||||||
|
|
||||||
const necessaryCategoryName = useMemo(
|
const necessaryCategoryName = useMemo(
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ func TestCookieBanner_Create(t *testing.T) {
|
|||||||
query($id: ID!) {
|
query($id: ID!) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
consentCategories(first: 10) {
|
categories(first: 10) {
|
||||||
totalCount
|
totalCount
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@@ -170,7 +170,7 @@ func TestCookieBanner_Create(t *testing.T) {
|
|||||||
|
|
||||||
var result struct {
|
var result struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
ConsentCategories struct {
|
Categories struct {
|
||||||
TotalCount int `json:"totalCount"`
|
TotalCount int `json:"totalCount"`
|
||||||
Edges []struct {
|
Edges []struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
@@ -179,16 +179,16 @@ func TestCookieBanner_Create(t *testing.T) {
|
|||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
} `json:"edges"`
|
} `json:"edges"`
|
||||||
} `json:"consentCategories"`
|
} `json:"categories"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
}
|
}
|
||||||
|
|
||||||
err := owner.Execute(query, map[string]any{"id": bannerID}, &result)
|
err := owner.Execute(query, map[string]any{"id": bannerID}, &result)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
assert.Greater(t, result.Node.ConsentCategories.TotalCount, 0)
|
assert.Greater(t, result.Node.Categories.TotalCount, 0)
|
||||||
|
|
||||||
kinds := make(map[string]bool)
|
kinds := make(map[string]bool)
|
||||||
for _, e := range result.Node.ConsentCategories.Edges {
|
for _, e := range result.Node.Categories.Edges {
|
||||||
kinds[e.Node.Kind] = true
|
kinds[e.Node.Kind] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -314,7 +314,7 @@ func TestCookieCategory_Delete(t *testing.T) {
|
|||||||
query($id: ID!) {
|
query($id: ID!) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
consentCategories(first: 20) {
|
categories(first: 20) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
id
|
id
|
||||||
@@ -329,14 +329,14 @@ func TestCookieCategory_Delete(t *testing.T) {
|
|||||||
|
|
||||||
var listResult struct {
|
var listResult struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
ConsentCategories struct {
|
Categories struct {
|
||||||
Edges []struct {
|
Edges []struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Kind string `json:"kind"`
|
Kind string `json:"kind"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
} `json:"edges"`
|
} `json:"edges"`
|
||||||
} `json:"consentCategories"`
|
} `json:"categories"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -345,7 +345,7 @@ func TestCookieCategory_Delete(t *testing.T) {
|
|||||||
|
|
||||||
var necessaryCategoryID string
|
var necessaryCategoryID string
|
||||||
|
|
||||||
for _, e := range listResult.Node.ConsentCategories.Edges {
|
for _, e := range listResult.Node.Categories.Edges {
|
||||||
if e.Node.Kind == "NECESSARY" {
|
if e.Node.Kind == "NECESSARY" {
|
||||||
necessaryCategoryID = e.Node.ID
|
necessaryCategoryID = e.Node.ID
|
||||||
break
|
break
|
||||||
@@ -423,7 +423,7 @@ func TestCookieCategory_List(t *testing.T) {
|
|||||||
query($id: ID!) {
|
query($id: ID!) {
|
||||||
node(id: $id) {
|
node(id: $id) {
|
||||||
... on CookieBanner {
|
... on CookieBanner {
|
||||||
consentCategories(first: 20, orderBy: {field: RANK, direction: ASC}) {
|
categories(first: 20, orderBy: {field: RANK, direction: ASC}) {
|
||||||
totalCount
|
totalCount
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@@ -443,7 +443,7 @@ func TestCookieCategory_List(t *testing.T) {
|
|||||||
|
|
||||||
var result struct {
|
var result struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
ConsentCategories struct {
|
Categories struct {
|
||||||
TotalCount int `json:"totalCount"`
|
TotalCount int `json:"totalCount"`
|
||||||
Edges []struct {
|
Edges []struct {
|
||||||
Node struct {
|
Node struct {
|
||||||
@@ -455,7 +455,7 @@ func TestCookieCategory_List(t *testing.T) {
|
|||||||
HasNextPage bool `json:"hasNextPage"`
|
HasNextPage bool `json:"hasNextPage"`
|
||||||
HasPreviousPage bool `json:"hasPreviousPage"`
|
HasPreviousPage bool `json:"hasPreviousPage"`
|
||||||
} `json:"pageInfo"`
|
} `json:"pageInfo"`
|
||||||
} `json:"consentCategories"`
|
} `json:"categories"`
|
||||||
} `json:"node"`
|
} `json:"node"`
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,13 +463,13 @@ func TestCookieCategory_List(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
// Default categories + 2 custom ones
|
// Default categories + 2 custom ones
|
||||||
assert.GreaterOrEqual(t, result.Node.ConsentCategories.TotalCount, 4)
|
assert.GreaterOrEqual(t, result.Node.Categories.TotalCount, 4)
|
||||||
|
|
||||||
// Verify ordering (ranks should be ascending)
|
// Verify ordering (ranks should be ascending)
|
||||||
for i := 1; i < len(result.Node.ConsentCategories.Edges); i++ {
|
for i := 1; i < len(result.Node.Categories.Edges); i++ {
|
||||||
assert.GreaterOrEqual(t,
|
assert.GreaterOrEqual(t,
|
||||||
result.Node.ConsentCategories.Edges[i].Node.Rank,
|
result.Node.Categories.Edges[i].Node.Rank,
|
||||||
result.Node.ConsentCategories.Edges[i-1].Node.Rank,
|
result.Node.Categories.Edges[i-1].Node.Rank,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -647,7 +647,7 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tps *TrackerPatterns) LoadUncategorisedByCookieBannerID(
|
func (tps *TrackerPatterns) LoadByCookieBannerID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
@@ -680,22 +680,14 @@ FROM
|
|||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND cookie_banner_id = @cookie_banner_id
|
AND cookie_banner_id = @cookie_banner_id
|
||||||
AND cookie_category_id = (
|
|
||||||
SELECT id FROM cookie_categories
|
|
||||||
WHERE cookie_banner_id = @cookie_banner_id
|
|
||||||
AND kind = @category_kind
|
|
||||||
AND %s
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
AND %s
|
AND %s
|
||||||
AND %s
|
AND %s
|
||||||
`
|
`
|
||||||
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment(), scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment(), cursor.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"cookie_banner_id": cookieBannerID,
|
"cookie_banner_id": cookieBannerID,
|
||||||
"category_kind": CookieCategoryKindUncategorised,
|
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
maps.Copy(args, filter.SQLArguments())
|
maps.Copy(args, filter.SQLArguments())
|
||||||
@@ -703,12 +695,12 @@ WHERE
|
|||||||
|
|
||||||
rows, err := conn.Query(ctx, q, args)
|
rows, err := conn.Query(ctx, q, args)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot query uncategorised tracker patterns: %w", err)
|
return fmt.Errorf("cannot query tracker patterns: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
patterns, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[TrackerPattern])
|
patterns, err := pgx.CollectRows(rows, pgx.RowToAddrOfStructByName[TrackerPattern])
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return fmt.Errorf("cannot collect uncategorised tracker patterns: %w", err)
|
return fmt.Errorf("cannot collect tracker patterns: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
*tps = patterns
|
*tps = patterns
|
||||||
@@ -716,7 +708,7 @@ WHERE
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (tps *TrackerPatterns) CountUncategorisedByCookieBannerID(
|
func (tps *TrackerPatterns) CountByCookieBannerID(
|
||||||
ctx context.Context,
|
ctx context.Context,
|
||||||
conn pg.Querier,
|
conn pg.Querier,
|
||||||
scope Scoper,
|
scope Scoper,
|
||||||
@@ -731,21 +723,13 @@ FROM
|
|||||||
WHERE
|
WHERE
|
||||||
%s
|
%s
|
||||||
AND cookie_banner_id = @cookie_banner_id
|
AND cookie_banner_id = @cookie_banner_id
|
||||||
AND cookie_category_id = (
|
|
||||||
SELECT id FROM cookie_categories
|
|
||||||
WHERE cookie_banner_id = @cookie_banner_id
|
|
||||||
AND kind = @category_kind
|
|
||||||
AND %s
|
|
||||||
LIMIT 1
|
|
||||||
)
|
|
||||||
AND %s
|
AND %s
|
||||||
`
|
`
|
||||||
|
|
||||||
q = fmt.Sprintf(q, scope.SQLFragment(), scope.SQLFragment(), filter.SQLFragment())
|
q = fmt.Sprintf(q, scope.SQLFragment(), filter.SQLFragment())
|
||||||
|
|
||||||
args := pgx.StrictNamedArgs{
|
args := pgx.StrictNamedArgs{
|
||||||
"cookie_banner_id": cookieBannerID,
|
"cookie_banner_id": cookieBannerID,
|
||||||
"category_kind": CookieCategoryKindUncategorised,
|
|
||||||
}
|
}
|
||||||
maps.Copy(args, scope.SQLArguments())
|
maps.Copy(args, scope.SQLArguments())
|
||||||
maps.Copy(args, filter.SQLArguments())
|
maps.Copy(args, filter.SQLArguments())
|
||||||
@@ -754,7 +738,7 @@ WHERE
|
|||||||
|
|
||||||
var count int
|
var count int
|
||||||
if err := row.Scan(&count); err != nil {
|
if err := row.Scan(&count); err != nil {
|
||||||
return 0, fmt.Errorf("cannot scan count: %w", err)
|
return 0, fmt.Errorf("cannot count tracker patterns: %w", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
return count, nil
|
return count, nil
|
||||||
|
|||||||
@@ -112,6 +112,13 @@ input CookieCategoryOrder
|
|||||||
field: CookieCategoryOrderField!
|
field: CookieCategoryOrderField!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input CookieCategoryFilter
|
||||||
|
@goModel(
|
||||||
|
model: "go.probo.inc/probo/pkg/server/api/console/v1/types.CookieCategoryFilter"
|
||||||
|
) {
|
||||||
|
excludeKind: CookieCategoryKind
|
||||||
|
}
|
||||||
|
|
||||||
type CookieBanner implements Node {
|
type CookieBanner implements Node {
|
||||||
id: ID!
|
id: ID!
|
||||||
name: String!
|
name: String!
|
||||||
@@ -125,12 +132,13 @@ type CookieBanner implements Node {
|
|||||||
|
|
||||||
organization: Organization @goField(forceResolver: true)
|
organization: Organization @goField(forceResolver: true)
|
||||||
|
|
||||||
consentCategories(
|
categories(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
last: Int
|
last: Int
|
||||||
before: CursorKey
|
before: CursorKey
|
||||||
orderBy: CookieCategoryOrder
|
orderBy: CookieCategoryOrder
|
||||||
|
filter: CookieCategoryFilter
|
||||||
): CookieCategoryConnection @goField(forceResolver: true)
|
): CookieCategoryConnection @goField(forceResolver: true)
|
||||||
|
|
||||||
translations: [CookieBannerTranslation!]! @goField(forceResolver: true)
|
translations: [CookieBannerTranslation!]! @goField(forceResolver: true)
|
||||||
@@ -146,7 +154,7 @@ type CookieBanner implements Node {
|
|||||||
filter: CookieConsentRecordFilter
|
filter: CookieConsentRecordFilter
|
||||||
): CookieConsentRecordConnection @goField(forceResolver: true)
|
): CookieConsentRecordConnection @goField(forceResolver: true)
|
||||||
|
|
||||||
uncategorisedTrackerPatterns(
|
trackerPatterns(
|
||||||
first: Int
|
first: Int
|
||||||
after: CursorKey
|
after: CursorKey
|
||||||
last: Int
|
last: Int
|
||||||
@@ -299,6 +307,7 @@ input TrackerPatternFilter
|
|||||||
query: String
|
query: String
|
||||||
source: CookieSource
|
source: CookieSource
|
||||||
trackerType: TrackerType
|
trackerType: TrackerType
|
||||||
|
cookieCategoryId: ID
|
||||||
}
|
}
|
||||||
|
|
||||||
enum TrackerResourceType
|
enum TrackerResourceType
|
||||||
|
|||||||
@@ -37,6 +37,7 @@ type (
|
|||||||
Query *string
|
Query *string
|
||||||
Source *coredata.CookieSource
|
Source *coredata.CookieSource
|
||||||
TrackerType *coredata.TrackerType
|
TrackerType *coredata.TrackerType
|
||||||
|
CookieCategoryID *gid.GID
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user