Add PostHog consent integration and extract integration plugin system
Add PostHog opt-in/opt-out consent support mirroring the existing Google Consent Mode integration: database column, GraphQL field, console UI toggle, and client-side posthog-js calls. Extract both GCM and PostHog logic from CookieBannerClient into a ConsentIntegration plugin interface so future integrations can be added without modifying the client core. Signed-off-by: Émile Ré <emile@getprobo.com>
This commit is contained in:
@@ -60,6 +60,7 @@ export const categorySectionFragment = graphql`
|
||||
description
|
||||
kind
|
||||
gcmConsentTypes
|
||||
posthogConsent
|
||||
cookies(first: 100, orderBy: { field: CREATED_AT, direction: ASC })
|
||||
@connection(key: "CategorySection_cookies", filters: [])
|
||||
@required(action: THROW) {
|
||||
@@ -99,6 +100,7 @@ const updateCategoryMutation = graphql`
|
||||
description
|
||||
rank
|
||||
gcmConsentTypes
|
||||
posthogConsent
|
||||
updatedAt
|
||||
}
|
||||
cookieBanner {
|
||||
@@ -239,7 +241,10 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
||||
const cookies = category.cookies.edges.map(e => e.node);
|
||||
const isMutating = isUpdating || isCreating || isUpdatingCookie;
|
||||
|
||||
const handleSaveCategory = (name: string, slug: string, description: string, gcmConsentTypes: string[]) => {
|
||||
const handleSaveCategory = (
|
||||
name: string, slug: string, description: string,
|
||||
gcmConsentTypes: string[], posthogConsent: boolean,
|
||||
) => {
|
||||
updateCategory({
|
||||
variables: {
|
||||
input: {
|
||||
@@ -248,6 +253,7 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
||||
slug,
|
||||
description,
|
||||
gcmConsentTypes,
|
||||
posthogConsent,
|
||||
},
|
||||
},
|
||||
onCompleted(_response, errors) {
|
||||
@@ -485,6 +491,7 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
||||
slug={category.slug}
|
||||
description={category.description}
|
||||
gcmConsentTypes={[...category.gcmConsentTypes]}
|
||||
posthogConsent={category.posthogConsent}
|
||||
isUpdating={isUpdating}
|
||||
onSave={handleSaveCategory}
|
||||
onCancel={() => setIsEditingCategory(false)}
|
||||
@@ -541,6 +548,16 @@ export function CategorySection({ categoryKey, onDelete }: CategorySectionProps)
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
{category.posthogConsent && (
|
||||
<div className="mt-2 flex items-center gap-1.5">
|
||||
<span className="text-xs text-txt-secondary/70">
|
||||
{__("PostHog:")}
|
||||
</span>
|
||||
<Badge variant="neutral">
|
||||
{__("Tracking consent")}
|
||||
</Badge>
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -31,8 +31,9 @@ interface EditCategoryFormProps {
|
||||
slug: string;
|
||||
description: string;
|
||||
gcmConsentTypes: string[];
|
||||
posthogConsent: boolean;
|
||||
isUpdating: boolean;
|
||||
onSave: (name: string, slug: string, description: string, gcmConsentTypes: string[]) => void;
|
||||
onSave: (name: string, slug: string, description: string, gcmConsentTypes: string[], posthogConsent: boolean) => void;
|
||||
onCancel: () => void;
|
||||
}
|
||||
|
||||
@@ -41,6 +42,7 @@ export function EditCategoryForm({
|
||||
slug,
|
||||
description,
|
||||
gcmConsentTypes,
|
||||
posthogConsent,
|
||||
isUpdating,
|
||||
onSave,
|
||||
onCancel,
|
||||
@@ -50,6 +52,7 @@ export function EditCategoryForm({
|
||||
const [editSlug, setEditSlug] = useState(slug);
|
||||
const [editDescription, setEditDescription] = useState(description);
|
||||
const [editGcmTypes, setEditGcmTypes] = useState<string[]>(gcmConsentTypes);
|
||||
const [editPosthogConsent, setEditPosthogConsent] = useState(posthogConsent);
|
||||
|
||||
const toggleGcmType = (type: string) => {
|
||||
setEditGcmTypes(prev =>
|
||||
@@ -102,11 +105,28 @@ export function EditCategoryForm({
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-sm font-medium">
|
||||
{__("PostHog")}
|
||||
</label>
|
||||
<p className="text-xs text-muted-foreground mb-2">
|
||||
{__("Control PostHog tracking consent based on this category.")}
|
||||
</p>
|
||||
<label className="flex items-center gap-1.5 text-xs cursor-pointer">
|
||||
<input
|
||||
type="checkbox"
|
||||
checked={editPosthogConsent}
|
||||
onChange={() => setEditPosthogConsent(prev => !prev)}
|
||||
className="rounded"
|
||||
/>
|
||||
<span>{__("Opt in/out of PostHog tracking")}</span>
|
||||
</label>
|
||||
</div>
|
||||
<div className="flex items-center gap-2">
|
||||
<Button
|
||||
onClick={() => {
|
||||
if (!/^[a-z0-9]+(-[a-z0-9]+)*$/.test(editSlug)) return;
|
||||
onSave(editName, editSlug, editDescription, editGcmTypes);
|
||||
onSave(editName, editSlug, editDescription, editGcmTypes, editPosthogConsent);
|
||||
}}
|
||||
disabled={isUpdating}
|
||||
>
|
||||
|
||||
@@ -24,6 +24,8 @@ import { NotFoundError } from "./errors";
|
||||
import { fetchJSON } from "./http";
|
||||
import type { BannerTexts } from "./i18n";
|
||||
import { detectLanguage } from "./i18n";
|
||||
import type { ConsentIntegration } from "./integrations";
|
||||
import { createDefaultIntegrations } from "./integrations";
|
||||
import { enqueue, flush } from "./queue";
|
||||
import { getOrCreateVisitorId } from "./visitor";
|
||||
|
||||
@@ -40,6 +42,7 @@ export interface Category {
|
||||
kind: string;
|
||||
cookies: CookieItem[];
|
||||
gcm_consent_types: string[];
|
||||
posthog_consent: boolean;
|
||||
}
|
||||
|
||||
export interface BannerConfig {
|
||||
@@ -84,6 +87,8 @@ export class CookieBannerClient {
|
||||
private readonly visitorId: string;
|
||||
private readonly lang: string;
|
||||
|
||||
private readonly integrations: ConsentIntegration[];
|
||||
|
||||
private bannerConfig: BannerConfig | null = null;
|
||||
private consent: VisitorConsent | null = null;
|
||||
private observer: MutationObserver | null = null;
|
||||
@@ -99,6 +104,7 @@ export class CookieBannerClient {
|
||||
this.bannerId = config.bannerId;
|
||||
this.visitorId = getOrCreateVisitorId(config.bannerId);
|
||||
this.lang = detectLanguage(config.lang);
|
||||
this.integrations = createDefaultIntegrations();
|
||||
}
|
||||
|
||||
async load(): Promise<void> {
|
||||
@@ -109,7 +115,9 @@ export class CookieBannerClient {
|
||||
const config = await fetchJSON<BannerConfig>(configUrl);
|
||||
this.bannerConfig = config;
|
||||
|
||||
this.setGoogleConsentDefaults();
|
||||
for (const integration of this.integrations) {
|
||||
integration.setDefaults(config.categories);
|
||||
}
|
||||
this.startDetector(config);
|
||||
|
||||
const cookie = getConsentCookie();
|
||||
@@ -274,7 +282,9 @@ export class CookieBannerClient {
|
||||
}
|
||||
|
||||
private activate(consentData: Record<string, boolean>): void {
|
||||
this.updateGoogleConsentMode(consentData);
|
||||
for (const integration of this.integrations) {
|
||||
integration.update(this.config.categories, consentData);
|
||||
}
|
||||
|
||||
const categoryCookies: Record<string, string[]> = {};
|
||||
const categoryLabels: Record<string, string> = {};
|
||||
@@ -293,55 +303,6 @@ export class CookieBannerClient {
|
||||
this.observer = observeAndActivate(consentData, categoryLabels, texts);
|
||||
}
|
||||
|
||||
private hasGCMMapping(): boolean {
|
||||
return this.config.categories.some(
|
||||
(cat) => cat.gcm_consent_types && cat.gcm_consent_types.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
private setGoogleConsentDefaults(): void {
|
||||
if (!this.hasGCMMapping()) return;
|
||||
|
||||
const w = window as unknown as Record<string, unknown>;
|
||||
const gtag = w.gtag as ((...args: unknown[]) => void) | undefined;
|
||||
if (typeof gtag !== "function") return;
|
||||
|
||||
const defaults: Record<string, string> = {};
|
||||
for (const cat of this.config.categories) {
|
||||
if (!cat.gcm_consent_types) continue;
|
||||
for (const gcmType of cat.gcm_consent_types) {
|
||||
defaults[gcmType] = "denied";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(defaults).length > 0) {
|
||||
gtag("consent", "default", defaults);
|
||||
}
|
||||
}
|
||||
|
||||
private updateGoogleConsentMode(
|
||||
consentData: Record<string, boolean>,
|
||||
): void {
|
||||
if (!this.hasGCMMapping()) return;
|
||||
|
||||
const w = window as unknown as Record<string, unknown>;
|
||||
const gtag = w.gtag as ((...args: unknown[]) => void) | undefined;
|
||||
if (typeof gtag !== "function") return;
|
||||
|
||||
const update: Record<string, string> = {};
|
||||
for (const cat of this.config.categories) {
|
||||
if (!cat.gcm_consent_types) continue;
|
||||
const granted = !!consentData[cat.slug];
|
||||
for (const gcmType of cat.gcm_consent_types) {
|
||||
update[gcmType] = granted ? "granted" : "denied";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(update).length > 0) {
|
||||
gtag("consent", "update", update);
|
||||
}
|
||||
}
|
||||
|
||||
private startDetector(config: BannerConfig): void {
|
||||
const knownNames = new Set<string>();
|
||||
knownNames.add(COOKIE_NAME);
|
||||
|
||||
73
packages/cookie-banner/src/integrations/gcm.ts
Normal file
73
packages/cookie-banner/src/integrations/gcm.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// 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 type { Category } from "../client";
|
||||
import type { ConsentIntegration } from "./integration";
|
||||
|
||||
export class GoogleConsentModeIntegration implements ConsentIntegration {
|
||||
private hasMapping(categories: Category[]): boolean {
|
||||
return categories.some(
|
||||
(cat) => cat.gcm_consent_types && cat.gcm_consent_types.length > 0,
|
||||
);
|
||||
}
|
||||
|
||||
private getGtag(): ((...args: unknown[]) => void) | null {
|
||||
const w = window as unknown as Record<string, unknown>;
|
||||
const gtag = w.gtag as ((...args: unknown[]) => void) | undefined;
|
||||
if (typeof gtag !== "function") return null;
|
||||
return gtag;
|
||||
}
|
||||
|
||||
setDefaults(categories: Category[]): void {
|
||||
if (!this.hasMapping(categories)) return;
|
||||
|
||||
const gtag = this.getGtag();
|
||||
if (!gtag) return;
|
||||
|
||||
const defaults: Record<string, string> = {};
|
||||
for (const cat of categories) {
|
||||
if (!cat.gcm_consent_types) continue;
|
||||
for (const gcmType of cat.gcm_consent_types) {
|
||||
defaults[gcmType] = "denied";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(defaults).length > 0) {
|
||||
gtag("consent", "default", defaults);
|
||||
}
|
||||
}
|
||||
|
||||
update(
|
||||
categories: Category[],
|
||||
consentData: Record<string, boolean>,
|
||||
): void {
|
||||
if (!this.hasMapping(categories)) return;
|
||||
|
||||
const gtag = this.getGtag();
|
||||
if (!gtag) return;
|
||||
|
||||
const update: Record<string, string> = {};
|
||||
for (const cat of categories) {
|
||||
if (!cat.gcm_consent_types) continue;
|
||||
const granted = !!consentData[cat.slug];
|
||||
for (const gcmType of cat.gcm_consent_types) {
|
||||
update[gcmType] = granted ? "granted" : "denied";
|
||||
}
|
||||
}
|
||||
|
||||
if (Object.keys(update).length > 0) {
|
||||
gtag("consent", "update", update);
|
||||
}
|
||||
}
|
||||
}
|
||||
28
packages/cookie-banner/src/integrations/index.ts
Normal file
28
packages/cookie-banner/src/integrations/index.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// 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.
|
||||
|
||||
export type { ConsentIntegration } from "./integration";
|
||||
export { GoogleConsentModeIntegration } from "./gcm";
|
||||
export { PostHogIntegration } from "./posthog";
|
||||
|
||||
import type { ConsentIntegration } from "./integration";
|
||||
import { GoogleConsentModeIntegration } from "./gcm";
|
||||
import { PostHogIntegration } from "./posthog";
|
||||
|
||||
export function createDefaultIntegrations(): ConsentIntegration[] {
|
||||
return [
|
||||
new GoogleConsentModeIntegration(),
|
||||
new PostHogIntegration(),
|
||||
];
|
||||
}
|
||||
23
packages/cookie-banner/src/integrations/integration.ts
Normal file
23
packages/cookie-banner/src/integrations/integration.ts
Normal file
@@ -0,0 +1,23 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// 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 type { Category } from "../client";
|
||||
|
||||
export interface ConsentIntegration {
|
||||
/** Called once after config is loaded, before any consent is applied. */
|
||||
setDefaults(categories: Category[]): void;
|
||||
|
||||
/** Called whenever consent changes (accept, reject, customize, GPC). */
|
||||
update(categories: Category[], consentData: Record<string, boolean>): void;
|
||||
}
|
||||
69
packages/cookie-banner/src/integrations/posthog.ts
Normal file
69
packages/cookie-banner/src/integrations/posthog.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
// Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
//
|
||||
// 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 type { Category } from "../client";
|
||||
import type { ConsentIntegration } from "./integration";
|
||||
|
||||
interface PostHogInstance {
|
||||
opt_in_capturing: () => void;
|
||||
opt_out_capturing: () => void;
|
||||
}
|
||||
|
||||
export class PostHogIntegration implements ConsentIntegration {
|
||||
private hasMapping(categories: Category[]): boolean {
|
||||
return categories.some((cat) => cat.posthog_consent);
|
||||
}
|
||||
|
||||
private getPostHog(): PostHogInstance | null {
|
||||
const w = window as unknown as Record<string, unknown>;
|
||||
const posthog = w.posthog as (PostHogInstance & Record<string, unknown>) | undefined;
|
||||
if (
|
||||
!posthog ||
|
||||
typeof posthog.opt_in_capturing !== "function" ||
|
||||
typeof posthog.opt_out_capturing !== "function"
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return posthog;
|
||||
}
|
||||
|
||||
setDefaults(categories: Category[]): void {
|
||||
if (!this.hasMapping(categories)) return;
|
||||
|
||||
const posthog = this.getPostHog();
|
||||
if (!posthog) return;
|
||||
|
||||
posthog.opt_out_capturing();
|
||||
}
|
||||
|
||||
update(
|
||||
categories: Category[],
|
||||
consentData: Record<string, boolean>,
|
||||
): void {
|
||||
if (!this.hasMapping(categories)) return;
|
||||
|
||||
const posthog = this.getPostHog();
|
||||
if (!posthog) return;
|
||||
|
||||
const granted = categories
|
||||
.filter((cat) => cat.posthog_consent)
|
||||
.every((cat) => !!consentData[cat.slug]);
|
||||
|
||||
if (granted) {
|
||||
posthog.opt_in_capturing();
|
||||
} else {
|
||||
posthog.opt_out_capturing();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -74,6 +74,7 @@ type (
|
||||
Slug *string
|
||||
Description *string
|
||||
GCMConsentTypes *[]string
|
||||
PostHogConsent *bool
|
||||
}
|
||||
|
||||
CreateCookieRequest struct {
|
||||
@@ -360,6 +361,7 @@ func buildSnapshot(
|
||||
Kind: c.Kind,
|
||||
Cookies: cookies,
|
||||
GCMConsentTypes: gcmConsentTypes,
|
||||
PostHogConsent: c.PostHogConsent,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1347,6 +1349,9 @@ func (s *Service) UpdateCookieCategory(
|
||||
if req.GCMConsentTypes != nil {
|
||||
category.GCMConsentTypes = *req.GCMConsentTypes
|
||||
}
|
||||
if req.PostHogConsent != nil {
|
||||
category.PostHogConsent = *req.PostHogConsent
|
||||
}
|
||||
|
||||
category.UpdatedAt = time.Now()
|
||||
|
||||
|
||||
@@ -55,6 +55,7 @@ type (
|
||||
Kind CookieCategoryKind `json:"kind"`
|
||||
Cookies CookieItems `json:"cookies"`
|
||||
GCMConsentTypes []string `json:"gcm_consent_types"`
|
||||
PostHogConsent bool `json:"posthog_consent"`
|
||||
}
|
||||
|
||||
CookieBannerVersion struct {
|
||||
|
||||
@@ -48,6 +48,7 @@ type (
|
||||
Kind CookieCategoryKind `db:"kind"`
|
||||
Rank int `db:"rank"`
|
||||
GCMConsentTypes []string `db:"gcm_consent_types"`
|
||||
PostHogConsent bool `db:"posthog_consent"`
|
||||
CreatedAt time.Time `db:"created_at"`
|
||||
UpdatedAt time.Time `db:"updated_at"`
|
||||
}
|
||||
@@ -111,6 +112,7 @@ SELECT
|
||||
kind,
|
||||
rank,
|
||||
gcm_consent_types,
|
||||
posthog_consent,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
@@ -162,6 +164,7 @@ SELECT
|
||||
kind,
|
||||
rank,
|
||||
gcm_consent_types,
|
||||
posthog_consent,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
@@ -241,6 +244,7 @@ SELECT
|
||||
kind,
|
||||
rank,
|
||||
gcm_consent_types,
|
||||
posthog_consent,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
@@ -289,6 +293,7 @@ INSERT INTO cookie_categories (
|
||||
kind,
|
||||
rank,
|
||||
gcm_consent_types,
|
||||
posthog_consent,
|
||||
created_at,
|
||||
updated_at
|
||||
) VALUES (
|
||||
@@ -302,6 +307,7 @@ INSERT INTO cookie_categories (
|
||||
@kind,
|
||||
@rank,
|
||||
@gcm_consent_types,
|
||||
@posthog_consent,
|
||||
@created_at,
|
||||
@updated_at
|
||||
)
|
||||
@@ -318,6 +324,7 @@ INSERT INTO cookie_categories (
|
||||
"kind": c.Kind,
|
||||
"rank": c.Rank,
|
||||
"gcm_consent_types": c.GCMConsentTypes,
|
||||
"posthog_consent": c.PostHogConsent,
|
||||
"created_at": c.CreatedAt,
|
||||
"updated_at": c.UpdatedAt,
|
||||
}
|
||||
@@ -347,6 +354,7 @@ SET
|
||||
slug = @slug,
|
||||
description = @description,
|
||||
gcm_consent_types = @gcm_consent_types,
|
||||
posthog_consent = @posthog_consent,
|
||||
updated_at = @updated_at
|
||||
WHERE
|
||||
%s
|
||||
@@ -361,6 +369,7 @@ WHERE
|
||||
"slug": c.Slug,
|
||||
"description": c.Description,
|
||||
"gcm_consent_types": c.GCMConsentTypes,
|
||||
"posthog_consent": c.PostHogConsent,
|
||||
"updated_at": c.UpdatedAt,
|
||||
}
|
||||
maps.Copy(args, scope.SQLArguments())
|
||||
@@ -477,6 +486,7 @@ SELECT
|
||||
kind,
|
||||
rank,
|
||||
gcm_consent_types,
|
||||
posthog_consent,
|
||||
created_at,
|
||||
updated_at
|
||||
FROM
|
||||
|
||||
16
pkg/coredata/migrations/20260424T112802Z.sql
Normal file
16
pkg/coredata/migrations/20260424T112802Z.sql
Normal file
@@ -0,0 +1,16 @@
|
||||
-- Copyright (c) 2026 Probo Inc <hello@getprobo.com>.
|
||||
--
|
||||
-- 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.
|
||||
|
||||
ALTER TABLE cookie_categories ADD COLUMN posthog_consent BOOLEAN NOT NULL DEFAULT false;
|
||||
ALTER TABLE cookie_categories ALTER COLUMN posthog_consent DROP DEFAULT;
|
||||
@@ -472,6 +472,7 @@ func (r *mutationResolver) UpdateCookieCategory(ctx context.Context, input types
|
||||
Slug: input.Slug,
|
||||
Description: input.Description,
|
||||
GCMConsentTypes: gcmConsentTypes,
|
||||
PostHogConsent: input.PosthogConsent,
|
||||
},
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -124,6 +124,7 @@ type CookieCategory implements Node {
|
||||
kind: CookieCategoryKind!
|
||||
rank: Int!
|
||||
gcmConsentTypes: [String!]!
|
||||
posthogConsent: Boolean!
|
||||
|
||||
cookies(
|
||||
first: Int
|
||||
@@ -310,6 +311,7 @@ input UpdateCookieCategoryInput {
|
||||
slug: String
|
||||
description: String
|
||||
gcmConsentTypes: [String!]
|
||||
posthogConsent: Boolean
|
||||
}
|
||||
|
||||
input DeleteCookieCategoryInput {
|
||||
|
||||
@@ -76,6 +76,7 @@ func NewCookieCategory(c *coredata.CookieCategory) *CookieCategory {
|
||||
Kind: c.Kind,
|
||||
Rank: c.Rank,
|
||||
GcmConsentTypes: gcmConsentTypes,
|
||||
PosthogConsent: c.PostHogConsent,
|
||||
CreatedAt: c.CreatedAt,
|
||||
UpdatedAt: c.UpdatedAt,
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user